home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 12 / Cream of the Crop 12 (Part II) / Cream of the Crop 12 (Part II).iso / OS2 / KONSTR21.ZIP / konstr / SOURCE / car.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1996-03-22  |  88.4 KB  |  3,870 lines

  1. #include "easy.h"
  2. #include "car.h"
  3.  
  4. #include <math.h>
  5. #include <ctype.h>
  6.  
  7. Program program;
  8.  
  9. const int maxcomment=2048;
  10.  
  11. String loadname("");
  12.  
  13. FontSelector fontselector;
  14.  
  15. Profile profile("CAR");
  16.  
  17. // ***** Some help functions **************
  18.  
  19. char *stripnl (char *p)
  20. {    long size=strlen(p);
  21.     if (size>0 && p[size-1]=='\n') p[size-1]=0;
  22.     return p;
  23. }
  24.  
  25. // *********** Counters **************************
  26.  
  27. class Count;
  28. class Counts
  29. {    Count *First;
  30.     public :
  31.     Counts () : First(0) {}
  32.     void add (Count *c);
  33.     void reset ();
  34. } counts;
  35.  
  36. class Count
  37. {    long C;
  38.     Count *Next;
  39.     public :
  40.     Count () : C(1),Next(0) { counts.add(this); }
  41.     Count (int start) : C(start),Next(0) {}
  42.     void reset () { C=1; }
  43.     long count () { C++; return C-1; }
  44.     void next (Count *n) { Next=n; }
  45.     Count *next () { return Next; }
  46. };
  47.  
  48. void Counts::add (Count *c)
  49. {    c->next(First);
  50.     First=c;
  51. }
  52.  
  53. void Counts::reset ()
  54. {    Count *c=First;
  55.     while (c)
  56.     {    c->reset();
  57.         c=c->next();
  58.     }
  59. }
  60.  
  61. //*************** Translation of Names **************
  62.  
  63. class TranslationList
  64. {    String Original,Pseudo;
  65.     TranslationList *Next;
  66.     public :
  67.     TranslationList (char *o, char *ps) :
  68.         Next(0),Original(o),Pseudo(ps)
  69.     {}
  70.     ~TranslationList ()
  71.     {    if (Next) delete Next;
  72.     }
  73.     void next (TranslationList *n) { Next=n; }
  74.     TranslationList *next () { return Next; }
  75.     void append (TranslationList *n)
  76.     {    if (!Next) Next=n;
  77.         else Next->append(n);
  78.     }
  79.     char *translate (char *ps);
  80. };
  81.  
  82. TranslationList *translation=0;
  83.  
  84. // ******* Action classes, handle user click in window ********
  85.  
  86. class Action // generic
  87. {    public :
  88.     Flag drag; // drag action or click action
  89.     Action () {}
  90.     virtual void perform (long x, long y) {}
  91.         // called, if the user clicked with botton 1
  92.     virtual void dragperform (int type, long x, long y) {}
  93.         // called, if the user drags with the mouse and if
  94.         // supported by the specific action
  95.     virtual void inform () {}
  96.         // inform user through toolbox
  97.     virtual void start () {}
  98.         // called, if the user chooses the action
  99.     virtual void abort () {}
  100.         // called, if the user chooses a different action
  101.     virtual int finished () { return 1; }
  102. };
  103.  
  104. class NoAction : public Action // unimplemented action
  105. {    public :
  106.     virtual void inform ();
  107. } noaction;
  108.  
  109. // ******* Window class ********
  110.  
  111. class MyBitmapPS : public BitmapPS
  112. {    public :
  113.     Flag invalid;
  114.     MyBitmapPS (Window &w) : BitmapPS(w),invalid(0) {}
  115. };
  116.  
  117. MyBitmapPS *bitmap=0;
  118.     // Pointer to window bitmap presentation space
  119.     // for keeping the drawing
  120.  
  121. class MainWindow : public StandardWindow
  122. {    double X1,X2,Y1,Y2, // math coordinates
  123.         Pixel, // pixel size in math coordinates
  124.         Xm,Ym; // midpoint of window
  125.     Action *A; // present action called through click handler
  126.     Action *OldA; // note the previous action
  127.     void compute (); // fit the coordinates to window size
  128.     public :
  129.     Flag showhidden, // show hidden objects or not
  130.         active, // window can redraw objects
  131.         square, // window must be square
  132.         sizing; // windows does already react to resizing
  133.     MainWindow () :
  134.         StandardWindow(ID_Window,String(1),
  135.             StandardWindow::normal|
  136.             StandardWindow::menu|
  137.             StandardWindow::keys|
  138.             StandardWindow::vscrollbar|
  139.             StandardWindow::hscrollbar),
  140.             showhidden(0),active(0),sizing(0)
  141.     {   init();
  142.         X1=-1; X2=1; Y1=-1; Y2=1;
  143.         A=&noaction;
  144.         compute();
  145.         settitle();
  146.     }
  147.     virtual void sized ();
  148.     virtual void redraw (PS &ps);
  149.     virtual void clicked (LONG x, LONG y, clicktype click,
  150.         int state);
  151.         // click handler
  152.     virtual int key (int flags, int code, int scan);
  153.         // key handler
  154.     long col (double x)
  155.     {    return (x-X1)/(X2-X1)*width();
  156.     }
  157.     long row (double y)
  158.     {    return (y-Y1)/(Y2-Y1)*height();
  159.     }
  160.     double x (long col)
  161.     {    return (double)col/width()*(X2-X1)+X1;
  162.     }
  163.     double y (long row)
  164.     {    return (double)row/height()*(Y2-Y1)+Y1;
  165.     }
  166.     void abort ()
  167.     {    A->abort(); A->start(); A->inform();
  168.     }
  169.     void action (Action &a)
  170.     {    OldA=A; A->abort(); A=&a; a.start(); a.inform();
  171.     }
  172.     void old ()
  173.     {    if (!OldA) return;
  174.         A=OldA; A->start(); A->inform();
  175.     }
  176.     double x1 () { return X1; }
  177.     double x2 () { return X2; }
  178.     double y1 () { return Y1; }
  179.     double y2 () { return Y2; }
  180.     double pixel () { return Pixel; }
  181.     virtual int vscrolled (int scroll, int pos);
  182.     virtual int hscrolled (int scroll, int pos);
  183.     void zoomin ();
  184.     void zoomout ();
  185.     void center ();
  186.     void setsize (double x1, double x2, double y1, double y2);
  187.     virtual void pres_changed () { sized(); update(); }
  188.     void settitle ();
  189.     virtual int close ();
  190. } window;
  191.  
  192. Menu menu(window);
  193. Help help(window,ID_Helptable,String(19),String(20));
  194.  
  195. // ********* Dialog for Multiple Object Selection ***
  196.  
  197. Dialog objectsdialog(window,IDD_Objects,help,2000); // the dialog
  198.  
  199. class ObjectsItem : public ListItem // list box handling class
  200. {    public :
  201.     ObjectsItem() : ListItem(ID_Objects,objectsdialog) {}
  202.     virtual void init ();
  203.     virtual void notify ();
  204. } objectsitem;
  205.  
  206. // ******* Input/Output class **********************
  207.  
  208. const int maxstrings=8;
  209.  
  210. class Strings
  211. {    String S[maxstrings];
  212.     int N;
  213.     public :
  214.     Strings () { N=0; }
  215.     int add (char *text);
  216.     String & operator [] (int i) { return S[i]; }
  217.     String * s () { return S; }
  218.     int n () { return N; }
  219.     void clear () { N=0; }
  220. };
  221.  
  222. const int maxleft=8;
  223.  
  224. int Strings::add (char *text)
  225. {   if (N>=maxstrings) return 0;
  226.     if (strlen(text)+1>S[N].size()) return 0;
  227.     strcpy(S[N++],text);
  228.     return 1;
  229. }
  230.  
  231. class Object;
  232. class Input
  233. {    Strings Left[maxleft];
  234.     int Nleft;
  235.     String Name;
  236.     Strings Right;
  237.     public :
  238.     Input () { Nleft=0; }
  239.     char *getstring (String &s, char *p);
  240.     int read (char *line);
  241.     int nleft () { return Nleft; }
  242.     Strings * left () { return Left; }
  243.     int nright () { return Right.n(); }
  244.     String *right () { return Right.s(); }
  245.     char *name () { return Name; }
  246.     Object *object (int n, int flags);
  247.     int set (Object &o, int n);
  248. } input;
  249.  
  250. int Input::read (char *l)
  251. {   String s;
  252.     Nleft=0;
  253.     while (1)
  254.     {    if (Nleft>=maxleft) return 0;
  255.         Left[Nleft].clear();
  256.         l=getstring(s,l); Left[Nleft].add(s);
  257.         if (*l++!='(') return 0;
  258.         if (*l!=')')
  259.             while (1)
  260.             {   l=getstring(s,l);
  261.                 if (!Left[Nleft].add(s)) return 0;
  262.                 if (*l==')') break;
  263.                 if (*l++!=',') return 0;
  264.             }
  265.         l++;
  266.         Nleft++;
  267.         if (*l=='=') break;
  268.         if (*l++!=',') return 0;
  269.     }
  270.     l++;
  271.     l=getstring(Name,l);
  272.     if (*l++!='(') return 0;
  273.     Right.clear();
  274.     while (1)
  275.     {    l=getstring(s,l); if (!Right.add(s)) return 0;
  276.         if (*l==')') break;
  277.         if (*l++!=',') return 0;
  278.     }
  279.     l++;
  280.     if (*l!=';') return 0;
  281.     return 1;
  282. }
  283.  
  284. char *Input::getstring (String &s, char *p)
  285. {    char *q=s;
  286.     long length=0;
  287.     while (*p==' ') p++;
  288.     if (*p=='"')
  289.     {   p++;
  290.         while (*p && *p!='"')
  291.         {    *q++=*p++; length++;
  292.             if (length>=String::defaultsize-1) break;
  293.         }
  294.         if (*p=='"') p++;
  295.     }
  296.     else
  297.     {    while (*p && *p!=',' && *p!=')' && *p!='=' && *p!='(')
  298.         {    *q++=*p++; length++;
  299.             if (length>=String::defaultsize-1) break;
  300.         }
  301.     }
  302.     while (*p==' ') p++;
  303.     *q=0;
  304.     return p;
  305. }
  306.  
  307. class Object;
  308. class IO
  309.     // serves as elder class for objects input and output
  310. {   protected :
  311.     char S[256];
  312.     String Name;
  313.     IO *Next;
  314.     public :
  315.     IO (char *name);
  316.     char *end () { return S+strlen(S); }
  317.     virtual char *write (Object &o);
  318.         // write objectname(flags),...=ioname(...)
  319.     void resadd (Object &o);
  320.         // add name of object, plus flags
  321.         // for use in reswrite
  322.     virtual void reswrite (Object &o) {}
  323.         // write left side in write
  324.     void depadd (Object &o);
  325.         // add name of object, for use in depwrite
  326.     virtual void depwrite (Object &o) {}
  327.         // write name of dependends ..., in write
  328.     void comma ();
  329.     IO *next () { return Next; }
  330.     void next (IO *io) { Next=io; }
  331.     char *name() { return Name; }
  332.     virtual int interpret (Input &i)
  333.         // interpret scanned input line
  334.     {    return 0;
  335.     }
  336. } defaultio("unimplemented");
  337.     // default IO is empty string
  338.  
  339. class IOList
  340.     // A list of IO instances for reading from file
  341. {    IO *First;
  342.     public :
  343.     IOList ()
  344.     {    First=0;
  345.     }
  346.     IO *first () { return First; }
  347.     void append (IO *io) { io->next(First); First=io; }
  348.     int interpret (char *line);
  349.     char *getstring (String &s, char *line);
  350. } iolist;
  351.  
  352. IO::IO (char *name) : Name(name)
  353. {    Next=0;
  354.     iolist.append(this);
  355. }
  356.  
  357. // ******** Objects, displayed in window ***********
  358.  
  359. class ObjectColors
  360. {   static long Light[6],Dark[6];
  361.     static char *Name[6];
  362.     int Defcolor;
  363.     int Chosen[6];
  364.     public :
  365.     void all ();
  366.     void none ();
  367.     ObjectColors () : Defcolor(0) { all(); }
  368.     int defcolor () { return Defcolor; }
  369.     void defcolor (int c) { Defcolor=c; }
  370.     long light (int i) { return Light[i]; }
  371.     long dark (int i) { return Dark[i]; }
  372.     long highlight () { return Colors::red; }
  373.     char *name (int i)
  374.     {    if (i>=0 && i<6) return Name[i];
  375.         else return Name[0];
  376.     }
  377.     int index (char *name);
  378.     void choose (int i, int f) { Chosen[i]=f; }
  379.     int chosen (int i) { return Chosen[i]; }
  380. } objectcolors;
  381.  
  382. int ObjectColors::index (char *name)
  383. {    int i;
  384.     for (i=0; i<6; i++)
  385.         if (!strcmp(name,Name[i])) return i;
  386.     return 0;
  387. }
  388.  
  389. void ObjectColors::all ()
  390. {    for (int i=0; i<6; i++) Chosen[i]=1;
  391. }
  392.  
  393. void ObjectColors::none ()
  394. {    for (int i=0; i<6; i++) Chosen[i]=0;
  395. }
  396.  
  397. long ObjectColors::Light[6]=
  398. {    Colors::darkgray,Colors::blue,
  399.     Colors::pink,Colors::green,
  400.     Colors::cyan,Colors::yellow
  401. };
  402.  
  403. long ObjectColors::Dark[6]=
  404. {    Colors::black,Colors::darkblue,
  405.     Colors::darkpink,Colors::darkgreen,
  406.     Colors::darkcyan,Colors::brown
  407. };
  408.  
  409. char *ObjectColors::Name[6]=
  410. {    "black","blue","pink","green","cyan","brown"
  411. };
  412.  
  413. #define MAXDEP 3 // Maximal numbers of elders
  414. class Object // generic object designed for list membership (heap)
  415. {    Object *Next,*Previous; // chaining information
  416.     int Class; // class flags (point,line,moveable,circle,angle)
  417.     long Color; // color
  418.     String Name; // unique name
  419.     IO *Io; // pointer to output class
  420.     public :
  421.     Flag mark, // mark for several purposes
  422.         valid, // object valid (intersections may become invalid)
  423.         highlight, // if chosen for input
  424.         showname, // show name on screen
  425.         ishidden; // if hidden from output
  426.     enum { point=1,moveable=2,line=4,circle=8,angle=16};
  427.         // class flags
  428.     Object ();
  429.     virtual void deletetrack () {}
  430.         // remove track from a point, if it has one
  431.     ~Object () { deletetrack(); }
  432.     Object *next() { return Next; }
  433.     Object *previous() { return Previous; }
  434.     void next (Object *o) { Next=o; }
  435.     void previous (Object *o) { Previous=o; }
  436.     virtual void draw (PS &ps) {};
  437.     int objectclass () { return Class; }
  438.     void objectclass (int c) { Class=c; }
  439.     virtual double distance (double x, double y) { return 1e10; }
  440.         // compute distance from (x,y) to object
  441.     virtual void update () {} // compute new position
  442.     virtual int depmarked (); // any elders marked?
  443.     virtual int dep (Object *o[]) { return 0; }  // retunr elders
  444.     virtual Object *original () { return this; }
  445.         // return original for intersections
  446.     long color () // return color of object
  447.     {    if (highlight) return objectcolors.highlight();
  448.         else if (ishidden) return objectcolors.light(Color);
  449.         else return objectcolors.dark(Color);
  450.     }
  451.     long truecolor () { return Color; }
  452.     void setcolor (long c) { Color=c; }
  453.     int hidden ();
  454.         // object cannot be displayed,
  455.         // because it is either hidden and hidden objects are
  456.         // not shown, or it is invalid
  457.     char *name() { return Name; }
  458.     void setname (char *prefix, Count &count);
  459.     void setname (char *name);
  460.     void setname1 (char *name);
  461.     void setio (IO &io) { Io=&io; }
  462.     virtual int project (double &x, double &y) { return 1; }
  463.     char *write () { return Io->write(*this); }
  464.     virtual void writespecialflags (IO &io) {}
  465.     int setflags (Strings &s); // for input from file
  466.     virtual int setspecialflag (char *s) { return 0; }
  467.     virtual void edit () {} // edit dialog for object
  468. };
  469.  
  470. class ObjectList // list of generic objects
  471. {    Object *First,*Last;
  472.     String Comment;
  473.     public :
  474.     Flag changed;
  475.     ObjectList () :
  476.         changed(0),Comment("",maxcomment),
  477.         First(0),Last(0)
  478.         {}
  479.     ~ObjectList ();
  480.     void draw (PS &ps);
  481.     void add (Object *o);
  482.     void remove (Object *o);
  483.     void insert (Object *o, Object *after);
  484.     int select (double x, double y, Object * &p,
  485.         int flags=0, int select=1, int mayhighlight=1);
  486.     void unmark (); // unmark all objects
  487.     void mark (Object *p); // mark p and dependends
  488.     void update (); // update all objects
  489.     void unhighlight (); // update all objects
  490.     void update (Object *p); // update p and dependends
  491.     void redraw (); // redraw bitmap and copy to screen
  492.     Object *first () { return First; }
  493.     Object *last () { return Last; }
  494.     void clear (); // remove all objects
  495.     void clear (Object *o); // remove Object and dependends
  496.     void deletetracks (); // remove Tracks from points
  497.     void save (char *filename); // save objects to file
  498.     void load (char *filename); // load objects from file
  499.     Object *find (char *name, int flags=0, Object *last=0);
  500.     String &comment () { return Comment; }
  501.     void copy (); // copy to clipboard
  502.     int empty () { return First==0; }
  503.     int exists (char *name);
  504. } objects;
  505.  
  506. Count objectcount;
  507.  
  508. Object::Object () : valid(1)
  509. {    Next=0; Previous=0; Class=0; Color=objectcolors.defcolor();
  510.     setname(String(2),objectcount);
  511.     setio(defaultio);
  512.     objects.add(this);
  513. }
  514.  
  515. inline int Object::hidden ()
  516. {    return ((ishidden && !window.showhidden) || !valid
  517.         || !objectcolors.chosen(Color));
  518. }
  519.  
  520. void Object::setname (char *s)
  521. {   if (objects.find(s)) return;
  522.     setname1(s);
  523. }
  524.  
  525. void Object::setname1 (char *s)
  526. {    char *p=s;
  527.     while (*p)
  528.     {    if (*p=='"') *p='\'';
  529.         p++;
  530.     }
  531.     Name.copy(s);
  532. }
  533.  
  534. int Object::depmarked (void)
  535. {    Object *o[MAXDEP];
  536.     int i,n;
  537.     n=dep(o);
  538.     for (i=0; i<n; i++)
  539.         if (o[i]->mark) return 1;
  540.     return 0;
  541. }
  542.  
  543. void Object::setname (char *prefix, Count &count)
  544. {   char s[256];
  545.     do
  546.     {    sprintf(s,"%s_%ld",prefix,count.count());
  547.     } while (objects.exists(s));
  548.     setname(s);
  549. }
  550.  
  551. ObjectList::~ObjectList ()
  552. {    Object *p=First,*p1;
  553.     while (p)
  554.     {    p1=p;
  555.         p=p->next();
  556.         delete p1;
  557.     }
  558. }
  559.  
  560. void ObjectList::draw (PS &ps)
  561. {    Object *p=First;
  562.     ps.erase();
  563.     while (p)
  564.     {    p->draw(ps);
  565.         p=p->next();
  566.     }
  567. }
  568.  
  569. void ObjectList::add (Object *o)
  570. {   if (Last) Last->next(o);
  571.     o->previous(Last);
  572.     o->next(0);
  573.     Last=o;
  574.     if (!First) First=Last;
  575.     changed.set();
  576. }
  577.  
  578. void ObjectList::remove (Object *o)
  579. {    Object *n=o->next(),*p=o->previous();
  580.     if (n) n->previous(p);
  581.     if (p) p->next(n);
  582.     if (Last==o) Last=p;
  583.     if (First==o) First=n;
  584.     delete o;
  585.     changed.set();
  586. }
  587.  
  588. void ObjectList::clear ()
  589. {    Object *o=First,*on;
  590.     while (o)
  591.     {   on=o->next();
  592.         delete o;
  593.         o=on;
  594.     }
  595.     First=Last=0;
  596.     changed.clear();
  597. }
  598.  
  599. void ObjectList::clear (Object *o)
  600. {   Object *p=First,*pn;
  601.     o=o->original();
  602.     mark(o);
  603.     while (p)
  604.     {   pn=p->next();
  605.         if (p->mark) remove(p);
  606.         p=pn;
  607.     }
  608. }
  609.  
  610. void ObjectList::insert (Object *o, Object *after)
  611. {    Object *p=after->next();
  612.     after->next(o);
  613.     o->next(p);
  614.     if (p) p->previous(o);
  615.     o->previous(after);
  616.     if (Last==after) Last=o;
  617. }
  618.  
  619. void ObjectList::unmark ()
  620. {    Object *p=First;
  621.     while (p)
  622.     {    p->mark.clear();
  623.         p=p->next();
  624.     }
  625. }
  626.  
  627. void ObjectList::mark (Object *p)
  628. {    unmark();
  629.     p=p->original();
  630.     p->mark.set();
  631.     while (p)
  632.     {    if (p->depmarked()) p->mark.set();
  633.         p=p->next();
  634.     }
  635. }
  636.  
  637. void ObjectList::update ()
  638. {    Object *p=First;
  639.     while (p)
  640.     {    p->update();
  641.         p=p->next();
  642.     }
  643. }
  644.  
  645. void ObjectList::unhighlight ()
  646. {    Object *p=First;
  647.     while (p)
  648.     {    p->highlight.clear();
  649.         p=p->next();
  650.     }
  651. }
  652.  
  653. void ObjectList::update (Object *p)
  654. {   mark(p);
  655.     while (p)
  656.     {    if (p->mark) p->update();
  657.         p=p->next();
  658.     }
  659.     changed.set();
  660. }
  661.  
  662. void ObjectList::redraw ()
  663. {   if (bitmap)
  664.     {    draw(*bitmap);
  665.         bitmap->copy(WindowPS(window));
  666.     }
  667. }
  668.  
  669. int ObjectList::select (double x, double y, Object * &pret,
  670.     int flags, int select, int mayhighlight)
  671. {    double r=window.pixel()*4;
  672.     Object *p=First,*ps=0;
  673.     int count=0,n;
  674.     objects.unmark();
  675.     while (p)
  676.     {    if ((!flags || (p->objectclass()&flags))
  677.             && p->valid && !p->hidden() && p->distance(x,y)<r
  678.             && (mayhighlight || !p->highlight))
  679.         {   p->mark.set();
  680.             if (pret && p==pret) return 1;
  681.             ps=p;
  682.             count++;
  683.         }
  684.         p=p->next();
  685.     }
  686.     if (ps) pret=ps;
  687.     if (count==0) return 0;
  688.     if (count==1) return count;
  689.     if (!select) return count;
  690.     objectsdialog.carryout();
  691.     if (objectsdialog.result()!=DID_OK) return 0;
  692.     n=objectsitem;
  693.     p=objects.first();
  694.     while (p && n>=0)
  695.     {   if (p->mark)
  696.         {    pret=p; n--;
  697.         }
  698.         p=p->next();
  699.     }
  700.     return count;
  701. }
  702.  
  703. void ObjectsItem::init ()
  704. {   int count=0;
  705.     Object *p=objects.first();
  706.     while (p)
  707.     {    if (p->mark)
  708.         {    insert(p->name());
  709.             count++;
  710.         }
  711.         p=p->next();
  712.     }
  713.     select(count-1);
  714. }
  715.  
  716. void ObjectsItem::notify ()
  717. {    finish();
  718. }
  719.  
  720. Object *ObjectList::find (char *name, int flags, Object *last)
  721. {    Object *o=First;
  722.     if (translation) name=translation->translate(name);
  723.     if (!name) return 0;
  724.     while (o!=last)
  725.     {    if (!strcmp(name,o->name())
  726.             && (flags==0 || (o->objectclass()&flags))) return o;
  727.         o=o->next();
  728.     }
  729.     return 0;
  730. }
  731.  
  732. int ObjectList::exists (char *name)
  733. {    Object *o=First;
  734.     while (o!=last())
  735.     {    if (!strcmp(name,o->name())) return 1;
  736.         o=o->next();
  737.     }
  738.     return 0;
  739. }
  740.  
  741. // ************* window routines, redraw etc. *********
  742.  
  743. void MainWindow::compute ()
  744. {    Pixel=(X2-X1)/width();
  745.     Xm=(X2+X1)/2;
  746.     Ym=(Y2+Y1)/2;
  747.     Y1=Ym-Pixel*height()/2;
  748.     Y2=Ym+Pixel*height()/2;
  749.     vscroll(50);
  750.     hscroll(50);
  751. }
  752.  
  753. void MainWindow::setsize (double x1, double x2, double y1, double y2)
  754. {    if (x2<x1+1e-15 || y2<y1+1e-15) return;
  755.     X1=x1; X2=x2; Y1=y1; Y2=y2;
  756.     if ((y1-y2)/(x1-x2) < height()/width())
  757.         size(width(),width()*(y2-y1)/(x2-x1));
  758.     else
  759.         size(height()*(x2-x1)/(y2-y1),height());
  760.     compute();
  761. }
  762.  
  763. void MainWindow::zoomin ()
  764. {   Xm=(X2+X1)/2;
  765.     X1=Xm-(X2-X1)/2/1.2;
  766.     X2=Xm+(X2-X1)/2/1.2;
  767.     compute();
  768.     objects.redraw();
  769. }
  770.  
  771. void MainWindow::zoomout ()
  772. {   Xm=(X2+X1)/2;
  773.     X1=Xm-(X2-X1)/2*1.2;
  774.     X2=Xm+(X2-X1)/2*1.2;
  775.     compute();
  776.     objects.redraw();
  777. }
  778.  
  779. void MainWindow::center ()
  780. {    X1=-1;
  781.     X2=1;
  782.     compute();
  783.     objects.redraw();
  784. }
  785.  
  786. int MainWindow::vscrolled (int scroll, int pos)
  787. {   double r=0;
  788.     switch (scroll)
  789.     {    case Scroll::up : r=0.1; break;
  790.         case Scroll::down : r=-0.1; break;
  791.         case Scroll::pageup : r=0.5; break;
  792.         case Scroll::pagedown : r=-0.5; break;
  793.         default : return 0;
  794.     }
  795.     r*=(Y2-Y1); Y1+=r; Y2+=r;
  796.     compute();
  797.     objects.redraw();
  798.     objects.changed.set();
  799.     return 1;
  800. }
  801.  
  802. int MainWindow::hscrolled (int scroll, int pos)
  803. {   double r=0;
  804.     switch (scroll)
  805.     {    case Scroll::right : r=0.1; break;
  806.         case Scroll::left : r=-0.1; break;
  807.         case Scroll::pageright : r=0.5; break;
  808.         case Scroll::pageleft : r=-0.5; break;
  809.         default : return 0;
  810.     }
  811.     r*=(X2-X1); X1+=r; X2+=r;
  812.     compute();
  813.     objects.redraw();
  814.     objects.changed.set();
  815.     return 1;
  816. }
  817.  
  818. void MainWindow::sized ()
  819. {   if (!sizing) return;
  820.     compute();
  821.     if (square && (width() != height()))
  822.     {    size(height(),height()); return;
  823.     }
  824.     if (bitmap) delete bitmap;
  825.     bitmap=new MyBitmapPS(*this);
  826.     if (fontselector) bitmap->setfont(Font(fontselector));
  827.     if (active) bitmap->invalid.set();
  828.     objects.changed.set();
  829. }
  830.  
  831. void MainWindow::redraw (PS &ps)
  832. {   if (!active) return;
  833.     if (!bitmap) { ps.erase(); return; }
  834.     if (bitmap->invalid) objects.draw(*bitmap);
  835.     bitmap->invalid.clear();
  836.     bitmap->copy(ps);
  837. }
  838.  
  839. void MainWindow::settitle ()
  840. {    char s[256];
  841.     strcpy(s,String(1));
  842.     strcat(s," (");
  843.     if (!loadname.empty()) strcat(s,loadname.filename());
  844.     strcat(s,")");
  845.     title(s);
  846. }
  847.  
  848. // ******** Tracks ****************
  849.  
  850. const int tracksize=1024;
  851.  
  852. class Track
  853. {    double X[tracksize],Y[tracksize];
  854.     int Count;
  855.     int Color;
  856.     public :
  857.     Track () { Count=0; Color=Colors::def; }
  858.     void draw (PS &ps);
  859.     void add (double &x, double &y);
  860.     void start () { Count=0; }
  861. };
  862.  
  863. void Track::draw (PS &ps)
  864. {   int i;
  865.     if (Count<2) return;
  866.     ps.move(window.col(X[0]),window.row(Y[0]));
  867.     for (i=1; i<Count; i++)
  868.     {    ps.lineto(window.col(X[i]),window.row(Y[i]),Color);
  869.     }
  870. }
  871.  
  872. void Track::add (double &x, double &y)
  873. {    if (Count==tracksize) return;
  874.     X[Count]=x; Y[Count]=y; Count++;
  875. }
  876.  
  877. // ********** Tool dialog definition ****************
  878.  
  879. class ToolDialog : public DialogPanel
  880. {    public :
  881.     ToolDialog (Window &window, int id) :
  882.         DialogPanel(window,id,help,300) {}
  883.     virtual int handler (int command);
  884.     void inform (char *text) { settext(ID_Text,text); }
  885.     virtual int key (int flags, int code, int scan);
  886. } tools(window,IDD_Tools);
  887.  
  888. void dohidden ();
  889. void docolor ();
  890. void dobackspace ();
  891.  
  892. int ToolDialog::handler (int command)
  893. {    switch(command)
  894.     {    case ID_DeleteTracks :
  895.             objects.deletetracks();
  896.             objects.redraw();
  897.             return 1;
  898.         case ID_Hide :
  899.             dohidden();
  900.             return 1;
  901.         case ID_Colors :
  902.             docolor();
  903.             return 1;
  904.         case ID_Undo :
  905.             dobackspace();
  906.             return 1;
  907.     }
  908.     return 0;
  909. }
  910.  
  911. // ********** unimplemented action ********
  912.  
  913. void NoAction::inform ()
  914. {    tools.inform(String(4));
  915. }
  916.  
  917. // ********** Points *******
  918.  
  919. class Pointprim : public Object // point object
  920. {    double X,Y;
  921.     int Symbol;
  922.     static long Count;
  923.     Track *T; // Track of the point
  924.     public :
  925.     Pointprim (double x=0, double y=0);
  926.     double x() { return X; }
  927.     double y() { return Y; }
  928.     virtual void draw (PS &ps);
  929.     virtual double distance (double x, double y);
  930.     void set (double x, double y);
  931.     virtual void deletetrack ()
  932.     {    if (T) delete T;
  933.         T=0;
  934.         highlight.unfix();
  935.         highlight.clear();
  936.     }
  937.     void starttrack ()
  938.     {    if (!T) T=new Track;
  939.         else T->start();
  940.         T->add(X,Y);
  941.         highlight.set();
  942.         highlight.fix();
  943.     }
  944.     virtual void edit ();
  945.     virtual int setspecialflag (char *s);
  946.     virtual void writespecialflags (IO &io);
  947. };
  948.  
  949. Count pointcount;
  950.  
  951. class Point : public Pointprim
  952. {    public :
  953.     Point (double x, double y) : Pointprim(x,y)
  954.     {   objectclass(objectclass()|Object::moveable);
  955.         setname(String(5),pointcount);
  956.     }
  957. };
  958.  
  959. class PointIO : public IO
  960. {    public :
  961.     PointIO () : IO("point") {}
  962.     virtual void depwrite (Object &o);
  963.     virtual int interpret (Input &i);
  964. } pointio;
  965.  
  966. void PointIO::depwrite (Object &o)
  967. {   Pointprim &p=(Pointprim &)o;
  968.     sprintf(end(),"%g,%g",p.x(),p.y());
  969. }
  970.  
  971. int PointIO::interpret (Input &i)
  972. {    if (i.nleft()!=1 || i.nright()!=2) return 0;
  973.     double x,y;
  974.     if (!i.right()[0].todouble(x) || !i.right()[1].todouble(y))
  975.         return 0;
  976.     Point *P=new Point(x,y);
  977.     return i.set(*P,0);
  978. }
  979.  
  980. Pointprim::Pointprim (double x, double y) : Object()
  981. {    X=x, Y=y; objectclass(Object::point);
  982.     setio(pointio);
  983.     Symbol=Markers::square;
  984.     T=0;
  985. }
  986.  
  987. void ObjectList::deletetracks ()
  988. {    Object *o=First;
  989.     while (o)
  990.     {    o->deletetrack();
  991.         o=o->next();
  992.     }
  993. }
  994.  
  995. void Pointprim::draw (PS &ps)
  996. {   if (!valid || hidden()) return;
  997.     ps.mark(window.col(X),window.row(Y),Symbol,color());
  998.     if (T) T->draw(ps);
  999.     if (showname)
  1000.     {    ps.move(window.col(X)+5,window.row(Y));
  1001.         ps.text(name(),color(),TA_LEFT,TA_BOTTOM);    }
  1002. }
  1003.  
  1004. double Pointprim::distance (double x, double y)
  1005. {    double vx=x-X,vy=y-Y;
  1006.     return sqrt(vx*vx+vy*vy);
  1007. }
  1008.  
  1009. void Pointprim::set (double x, double y)
  1010. {    X=x; Y=y;
  1011.     if (T) T->add(x,y);
  1012. }
  1013.  
  1014. class PointAction : public Action // generate point
  1015. {    public :
  1016.     virtual void perform (long x, long y);
  1017.     virtual void inform ();
  1018. } pointaction;
  1019.  
  1020. void PointAction::inform ()
  1021. {    tools.inform(String(6));
  1022. }
  1023.  
  1024. void PointAction::perform (long c, long r)
  1025. {    double x=window.x(c),y=window.y(r);
  1026.     new Point(x,y);
  1027.     objects.redraw();
  1028. }
  1029.  
  1030. class PointColor : public ValuesetItem
  1031. {    public :
  1032.     PointColor (int id, Dialog &d, int r, int c)
  1033.         : ValuesetItem(id,d,r,c) {}
  1034.     virtual void init ();
  1035. };
  1036.  
  1037. void PointColor::init ()
  1038. {    int i;
  1039.     for (i=0; i<6; i++)
  1040.         setcolor(1,i+1,objectcolors.dark(i));
  1041.     ValuesetItem::init();
  1042. }
  1043.  
  1044. int radios[4] = { IDP_Square,IDP_Point,IDP_Circle,IDP_Cross };
  1045. int markertypes[4] = { Markers::square,
  1046.     Markers::dot,Markers::circle,Markers::cross };
  1047.  
  1048. void Pointprim::edit ()
  1049. {   int i;
  1050.     Dialog d(window,IDD_PointEdit,help,2010);
  1051.     StringItem nameitem(IDP_Name,d,name());
  1052.     PointColor coloritem(IDP_Color,d,1,truecolor()+1);
  1053.     CheckItem hideitem(IDP_Hidden,d,ishidden),
  1054.         shownameitem(IDP_ShowName,d,showname);
  1055.     StringItem lineitem(IDP_Line,d,stripnl(write()),512);
  1056.     lineitem.readonly();
  1057.     DoubleItem xitem(IDP_X,d,x()),yitem(IDP_Y,d,y());
  1058.     if (!(objectclass()&Object::moveable))
  1059.     {    xitem.readonly(); yitem.readonly();
  1060.     }
  1061.     for (i=0; i<4; i++)
  1062.         if (Symbol==markertypes[i]) break;
  1063.     if (i==4) i=0;
  1064.     RadioItem markeritem(radios,4,d,i+1);
  1065.     d.carryout();
  1066.     if (d.result()!=DID_OK) return;
  1067.     setname(nameitem);
  1068.     if (strcmp(nameitem,name()))
  1069.         Warning(String(48),String(1),window);
  1070.     if (objectclass()&Object::moveable) set(xitem,yitem);
  1071.     setcolor(coloritem.col()-1);
  1072.     ishidden=hideitem;
  1073.     showname=shownameitem;
  1074.     Symbol=markertypes[markeritem-1];
  1075. }
  1076.  
  1077. int Pointprim::setspecialflag (char *s)
  1078. {   if (!strncmp(s,"symbol:",7))
  1079.     {    if (!strcmp(s+7,"point")) Symbol=Markers::dot;
  1080.         else if (!strcmp(s+7,"cross")) Symbol=Markers::cross;
  1081.         else if (!strcmp(s+7,"square")) Symbol=Markers::square;
  1082.         else if (!strcmp(s+7,"circle")) Symbol=Markers::circle;
  1083.         else return 0;
  1084.         return 1;
  1085.     }
  1086.     return 0;
  1087. }
  1088.  
  1089. void Pointprim::writespecialflags (IO &io)
  1090. {   if (Symbol!=Markers::square)
  1091.     {   io.comma();
  1092.         strcat(io.end(),"symbol:");
  1093.         switch (Symbol)
  1094.         {    case Markers::dot : strcat(io.end(),"point"); break;
  1095.             case Markers::circle : strcat(io.end(),"circle"); break;
  1096.             case Markers::cross : strcat(io.end(),"cross"); break;
  1097.         }
  1098.     }
  1099. }
  1100.  
  1101. // ********** line routines ********
  1102.  
  1103. inline double max (double x, double y)
  1104. {    if (x>y) return x;
  1105.     return y;
  1106. }
  1107.  
  1108. class Lineprim : public Object // a line through two points
  1109. // this may actually be a line, a ray or a segment.
  1110. {   protected :
  1111.     double X,Y,X1,Y1,Vx,Vy,R;
  1112.     Pointprim *P1,*P2;
  1113.     public :
  1114.     Lineprim (Pointprim &p1, Pointprim &p2);
  1115.     double x() { return X; }
  1116.     double y() { return Y; }
  1117.     double x1() { return X1; }
  1118.     double y1() { return Y1; }
  1119.     double vx() { return Vx; }
  1120.     double vy() { return Vy; }
  1121.     virtual void draw (PS &ps);
  1122.     virtual void update ();
  1123.     virtual int dep (Object *o[])
  1124.     {    o[0]=P1; o[1]=P2; return 2;
  1125.     }
  1126.     virtual double distance (double x, double y);
  1127.     void intersect (Lineprim &L, Pointprim &P);
  1128.     double lambda (double x, double y);
  1129.         // det. lambda for point on line
  1130.     double length () { return R; }
  1131.     virtual int project (double &x, double &y);
  1132.     Pointprim *p1() { return P1; }
  1133.     Pointprim *p2() { return P2; }
  1134.     virtual void edit ();
  1135.     virtual int checkpoint (double x, double y) { return 1; }
  1136.         // Check if x,y is on the valid part of the ray or segment
  1137. };
  1138.  
  1139. Count linecount;
  1140.  
  1141. class Line : public Lineprim
  1142. {    public :
  1143.     Line (Pointprim &p1, Pointprim &p2) : Lineprim(p1,p2)
  1144.     {    setname(String(7),linecount);
  1145.     }
  1146. };
  1147.  
  1148. template<class Class>
  1149. class TwoPointIO : public IO
  1150. {    public :
  1151.     TwoPointIO (char *name) : IO(name) {}
  1152.     virtual void depwrite (Object &o)
  1153.     {    Class &l=(Class &)o;
  1154.         depadd(*l.p1()); comma(); depadd(*l.p2());
  1155.     }
  1156.     virtual int interpret (Input &i);
  1157. };
  1158.  
  1159. template<class Class> int TwoPointIO<Class>::interpret (Input &i)
  1160. {    if (i.nleft()!=1 || i.nright()!=2) return 0;
  1161.     Pointprim *p1=(Pointprim *)i.object(0,Object::point),
  1162.         *p2=(Pointprim *)i.object(1,Object::point);
  1163.     if (!p1 || !p2) return 0;
  1164.     Class *l=new Class(*p1,*p2);
  1165.     return i.set(*l,0);
  1166. }
  1167.  
  1168. TwoPointIO<Line> lineio("line");
  1169.  
  1170. Lineprim::Lineprim (Pointprim &p1, Pointprim &p2) : Object()
  1171. {    P1=&p1; P2=&p2;
  1172.     objectclass(Object::line);
  1173.     setio(lineio);
  1174.     update();
  1175. }
  1176.  
  1177. void Lineprim::update ()
  1178. {   valid.set();
  1179.     if (!P1->valid || !P2->valid)
  1180.     {    valid.clear(); return;
  1181.     }
  1182.     X=P1->x(); Y=P1->y(); X1=P2->x(); Y1=P2->y();
  1183.     Vx=X1-X; Vy=Y1-Y;
  1184.     R=sqrt(Vx*Vx+Vy*Vy);
  1185.     if (R<1e-15) valid.clear();
  1186.     else { valid.set(); Vx/=R; Vy/=R; }
  1187. }
  1188.  
  1189. void Lineprim::draw (PS &ps)
  1190. {   double x,y,hx,hy,d,r;
  1191.     if (!valid || hidden()) return;
  1192.     x=(window.x1()+window.x2())/2;
  1193.     y=(window.y1()+window.y2())/2;
  1194.     d=(x-X)*Vy-(y-Y)*Vx; x-=d*Vy; y+=d*Vx;
  1195.     r=max(window.x2()-window.x1(),window.y2()-window.y1())*2;
  1196.     ps.move(window.col(x-Vx*r),window.row(y-Vy*r));
  1197.     ps.lineto(window.col(x),window.row(y),color());
  1198.     ps.lineto(window.col(x+Vx*r),window.row(y+Vy*r),color());
  1199.     if (showname)
  1200.     {    double extend=ps.textextend(name(),Vy,-Vx);
  1201.         r=extend*window.pixel()/2;
  1202.         x+=30*window.pixel()*Vx; y+=30*window.pixel()*Vy;        x-=Vy*r; y+=Vx*r;
  1203.         ps.move(window.col(x),window.row(y));
  1204.         ps.text(name(),color(),TA_CENTER,TA_HALF);
  1205.     }
  1206. }
  1207.  
  1208. double Lineprim::distance (double x, double y)
  1209. {    return fabs((x-X)*Vy-(y-Y)*Vx);
  1210. }
  1211.  
  1212. void Lineprim::intersect (Lineprim &L, Pointprim &P)
  1213. {    double det=Vx*L.Vy-Vy*L.Vx,l;
  1214.     if (fabs(det)<1e-15)
  1215.     {    P.valid.clear();
  1216.         return;
  1217.     }
  1218.     l=((L.X-X)*L.Vy-(L.Y-Y)*L.Vx)/det;
  1219.     P.set(X+l*Vx,Y+l*Vy);
  1220.     if (!checkpoint(P.x(),P.y()) ||
  1221.         !L.checkpoint(P.x(),P.y())) P.valid.clear();
  1222.     else P.valid.set();
  1223. }
  1224.  
  1225. double Lineprim::lambda (double x, double y)
  1226. {    double vx=x-X,vy=y-Y;
  1227.     if (fabs(Vx)>fabs(Vy)) return vx/Vx;
  1228.     else return vy/Vy;
  1229. }
  1230.  
  1231. int Lineprim::project (double &x, double &y)
  1232. {    double l=(x-X)*Vx+(y-Y)*Vy;
  1233.     x=X+l*Vx; y=Y+l*Vy;
  1234.     return 1;
  1235. }
  1236.  
  1237. template<class Class>
  1238. class TwoPointAction : public Action // generate a line
  1239. {   protected :
  1240.     int State,I1,I2;
  1241.     Pointprim *P1,*P2;
  1242.     public :
  1243.     TwoPointAction (int i1, int i2) : I1(i1),I2(i2) {}
  1244.     virtual void perform (long x, long y);
  1245.     virtual void inform ();
  1246.     virtual void start ();
  1247.     virtual void abort ();
  1248.     virtual int finished () { return State==1; }
  1249. };
  1250.  
  1251. TwoPointAction<Line> lineaction(8,9);
  1252.  
  1253. template<class Class> void TwoPointAction<Class>::start ()
  1254. {    State=1;
  1255. }
  1256.  
  1257. template<class Class> void TwoPointAction<Class>::inform ()
  1258. {    switch (State)
  1259.     {    case 1 : tools.inform(String(I1)); break;
  1260.         case 2 : tools.inform(String(I2)); break;
  1261.     }
  1262. }
  1263.  
  1264. template<class Class>
  1265.     void TwoPointAction<Class>::perform (long c, long r)
  1266. {    double x=window.x(c),y=window.y(r);
  1267.     switch (State)
  1268.     {    case 1 :
  1269.             if (!objects.select(x,y,(Object *&)P1,Object::point))
  1270.                 return;
  1271.             P1->highlight.set(); objects.redraw();
  1272.             State=2; break;
  1273.         case 2 :
  1274.             if (!objects.select(x,y,(Object *&)P2,Object::point))
  1275.                 return;
  1276.             if (P1->distance(P2->x(),P2->y())<1e-15) return;
  1277.             State=1;
  1278.             P1->highlight.clear();
  1279.             new Class(*P1,*P2);
  1280.             objects.redraw();
  1281.             break;
  1282.     }
  1283.     inform();
  1284. }
  1285.  
  1286. template<class Class> void TwoPointAction<Class>::abort ()
  1287. {   if (State==2)
  1288.     {    P1->highlight.clear(); objects.redraw();
  1289.     }
  1290.     State=0;
  1291. }
  1292.  
  1293. void Lineprim::edit ()
  1294. {   Dialog d(window,IDD_LineEdit,help,2010);
  1295.     StringItem nameitem(IDP_Name,d,name());
  1296.     PointColor coloritem(IDP_Color,d,1,truecolor()+1);
  1297.     CheckItem hideitem(IDP_Hidden,d,ishidden),
  1298.         shownameitem(IDP_ShowName,d,showname);
  1299.     StringItem lineitem(IDP_Line,d,stripnl(write()),512);
  1300.     lineitem.readonly();
  1301.     DoubleItem ritem(IDL_Length,d,R);
  1302.     ritem.readonly();
  1303.     d.carryout();
  1304.     if (d.result()!=DID_OK) return;
  1305.     setname(nameitem);
  1306.     if (strcmp(nameitem,name()))
  1307.         Warning(String(48),String(1),window);
  1308.     setcolor(coloritem.col()-1);
  1309.     ishidden=hideitem;
  1310.     showname=shownameitem;
  1311. }
  1312.  
  1313. // ******* Ray Object ******************
  1314.  
  1315. class Ray : public Lineprim
  1316. {   public :
  1317.     Ray (Pointprim &p1, Pointprim &p2);
  1318.     virtual void draw (PS &ps);
  1319.     virtual double distance (double x, double y);
  1320.     virtual int checkpoint (double x, double y);
  1321. };
  1322.  
  1323. TwoPointIO<Ray> rayio("ray");
  1324.  
  1325. Count raycount;
  1326.  
  1327. Ray::Ray (Pointprim &p1, Pointprim &p2) : Lineprim(p1,p2)
  1328. {    setname(String(26),raycount);
  1329.     setio(rayio);
  1330. }
  1331.  
  1332. void Ray::draw (PS &ps)
  1333. {   double x,y,hx,hy,d,r,l,r1;
  1334.     if (!valid || hidden()) return;
  1335.     x=(window.x1()+window.x2())/2;
  1336.     y=(window.y1()+window.y2())/2;
  1337.     d=(x-X)*Vy-(y-Y)*Vx; x-=d*Vy; y+=d*Vx;
  1338.     r=max(window.x2()-window.x1(),window.y2()-window.y1())*2;
  1339.     l=-lambda(x,y);
  1340.     if (l>r) return;
  1341.     if (l>-r) r1=l;
  1342.     else r1=-r;
  1343.     ps.move(window.col(x+Vx*r1),window.row(y+Vy*r1));
  1344.     ps.lineto(window.col(x+Vx*r),window.row(y+Vy*r),color());
  1345.     if (showname)
  1346.     {   double extend=ps.textextend(name(),Vy,-Vx);
  1347.         r=extend*window.pixel()/2;
  1348.         x=(X+X1)/2; y=(Y+Y1)/2;        x-=Vy*r; y+=Vx*r;
  1349.         ps.move(window.col(x),window.row(y));
  1350.         ps.text(name(),color(),TA_CENTER,TA_HALF);
  1351.     }
  1352. }
  1353.  
  1354. double Ray::distance (double x, double y)
  1355. {    double r=Vx*(x-X)+Vy*(y-Y),vx,vy;
  1356.     if (r<0)
  1357.     {    vx=x-X; vy=y-Y; return sqrt(vx*vx+vy*vy);
  1358.     }
  1359.     else return Lineprim::distance(x,y);
  1360. }
  1361.  
  1362. int Ray::checkpoint (double x, double y)
  1363. {    if ((x-X)*Vx+(y-Y)*Vy>=-1e-15) return 1;
  1364.     else return 0;
  1365. }
  1366.  
  1367. TwoPointAction<Ray> rayaction(24,25);
  1368.  
  1369. // ******* Segment Object ******************
  1370.  
  1371. class Segment : public Lineprim
  1372. {    public :
  1373.     Segment (Pointprim &p1, Pointprim &p2);
  1374.     virtual void draw (PS &ps);
  1375.     virtual double distance (double x, double y);
  1376.     virtual int checkpoint (double x, double y);
  1377. };
  1378.  
  1379. TwoPointIO<Segment> segmentio("segment");
  1380.  
  1381. Count segmentcount;
  1382.  
  1383. Segment::Segment (Pointprim &p1, Pointprim &p2) : Lineprim(p1,p2)
  1384. {    setname(String(29),segmentcount);
  1385.     setio(segmentio);
  1386. }
  1387.  
  1388. void Segment::draw (PS &ps)
  1389. {   double x,y,hx,hy,d,r,l,r1;
  1390.     if (!valid || hidden()) return;
  1391.     x=(window.x1()+window.x2())/2;
  1392.     y=(window.y1()+window.y2())/2;
  1393.     d=(x-X)*Vy-(y-Y)*Vx; x-=d*Vy; y+=d*Vx;
  1394.     r=max(window.x2()-window.x1(),window.y2()-window.y1())*2;
  1395.     l=-lambda(x,y);
  1396.     if (l>r) return;
  1397.     if (l>-r) r1=l;
  1398.     else r1=-r;
  1399.     ps.move(window.col(x+Vx*r1),window.row(y+Vy*r1));
  1400.     l+=length();
  1401.     if (l>r) r1=r;
  1402.     else r1=l;
  1403.     ps.lineto(window.col(x+Vx*r1),window.row(y+Vy*r1),color());
  1404.     if (showname)
  1405.     {   double extend=ps.textextend(name(),Vy,-Vx);
  1406.         r=extend*window.pixel()/2;
  1407.         x=(X+X1)/2; y=(Y+Y1)/2;
  1408.         x-=Vy*r; y+=Vx*r;
  1409.         ps.move(window.col(x),window.row(y));
  1410.         ps.text(name(),color(),TA_CENTER,TA_HALF);
  1411.     }
  1412. }
  1413.  
  1414. double Segment::distance (double x, double y)
  1415. {    double r=Vx*(x-X)+Vy*(y-Y),vx,vy;
  1416.     if (r<0)
  1417.     {    vx=x-X; vy=y-Y; return sqrt(vx*vx+vy*vy);
  1418.     }
  1419.     else if (r>R)
  1420.     {    vx=x-X1; vy=y-Y1; return sqrt(vx*vx+vy*vy);
  1421.     }
  1422.     else return Lineprim::distance(x,y);
  1423. }
  1424.  
  1425. int Segment::checkpoint (double x, double y)
  1426. {    if ((x-X)*Vx+(y-Y)*Vy>=-1e-15 &&
  1427.         (x-X1)*Vx+(y-Y1)*Vy<=1e-15) return 1;
  1428.     else return 0;
  1429. }
  1430.  
  1431. TwoPointAction<Segment> segmentaction(27,28);
  1432.  
  1433. // ******** Circle object **************
  1434.  
  1435. class Circle : public Object // a circle through two points
  1436. {    double X,Y,X1,Y1,R;
  1437.     Pointprim *P1,*P2;
  1438.     public :
  1439.     Circle (Pointprim &p1, Pointprim &p2);
  1440.     double x() { return X; }
  1441.     double y() { return Y; }
  1442.     double x1() { return X1; }
  1443.     double y1() { return Y1; }
  1444.     double r() { return R; }
  1445.     virtual void draw (PS &ps);
  1446.     virtual void update ();
  1447.     virtual int dep (Object *o[])
  1448.     {    o[0]=P1; o[1]=P2; return 2;
  1449.     }
  1450.     virtual double distance (double x, double y);
  1451.     void intersect (Object &P, Pointprim &P1, Pointprim &P2);
  1452.     virtual int project (double &x, double &y);
  1453.     Pointprim *p1 () { return P1; }
  1454.     Pointprim *p2 () { return P2; }
  1455.     virtual void edit ();
  1456. };
  1457.  
  1458. TwoPointIO<Circle> circleio("circle");
  1459.  
  1460. Count circlecount;
  1461.  
  1462. Circle::Circle (Pointprim &p1, Pointprim &p2) : Object()
  1463. {    P1=&p1; P2=&p2;
  1464.     objectclass(Object::circle);
  1465.     setname(String(10),circlecount);
  1466.     setio(circleio);
  1467.     update();
  1468. }
  1469.  
  1470. void Circle::update ()
  1471. {   double Vx,Vy;
  1472.     valid.set();
  1473.     if (!P1->valid || !P2->valid)
  1474.     {    valid.clear(); return;
  1475.     }
  1476.     X=P1->x(); Y=P1->y(); X1=P2->x(); Y1=P2->y();
  1477.     Vx=X1-X; Vy=Y1-Y;
  1478.     R=sqrt(Vx*Vx+Vy*Vy);
  1479.     if (R<1e-15) valid.clear();
  1480.     else { valid.set(); }
  1481. }
  1482.  
  1483. void Circle::draw (PS &ps)
  1484. {   long c;
  1485.     double x,y,h;
  1486.     if (!valid || hidden()) return;
  1487.     c=window.col(X);
  1488.     ps.circle(c,window.row(Y),window.col(X+R)-c,1,color());
  1489.     if (showname)
  1490.     {   h=1/sqrt(2);
  1491.         x=X+R*h+10*window.pixel();
  1492.         y=Y-R*h-10*window.pixel();
  1493.         ps.move(window.col(x),window.row(y));
  1494.         ps.text(name(),color(),TA_CENTER,TA_HALF);
  1495.     }
  1496. }
  1497.  
  1498. double Circle::distance (double x, double y)
  1499. {    double rx=x-X,ry=y-Y;
  1500.     return fabs(sqrt(rx*rx+ry*ry)-R);
  1501. }
  1502.  
  1503. void Circle::intersect (Object &P, Pointprim &P1, Pointprim &P2)
  1504. {   double d,vx,vy,hx,hy;
  1505.     if (P.objectclass()&Object::line)
  1506.     {   Lineprim &L=(Lineprim &)P;
  1507.         d=L.vy()*(X-L.x())-L.vx()*(Y-L.y());
  1508.         if (fabs(d)>R)
  1509.         {    P1.valid.clear(); P2.valid.clear();
  1510.             return;
  1511.         }
  1512.         vx=-L.vy();
  1513.         vy=L.vx();
  1514.     }
  1515.     else
  1516.     {   Circle &C=(Circle &)P;
  1517.         vx=C.x()-x(); vy=C.y()-y();
  1518.         d=sqrt(vx*vx+vy*vy);
  1519.         if (d<1e-15 || d>C.r()+r() || d+C.r()<r() || d+r()<C.r())
  1520.         {    P1.valid.clear(); P2.valid.clear();
  1521.             return;
  1522.         }
  1523.         vx/=d; vy/=d;
  1524.         d=(r()*r()-C.r()*C.r()+d*d)/(2*d);
  1525.     }
  1526.     hx=X+d*vx; hy=Y+d*vy;
  1527.     d=sqrt(r()*r()-d*d);
  1528.     P1.set(hx+vy*d,hy-vx*d);
  1529.     P2.set(hx-vy*d,hy+vx*d);
  1530.     if (P.objectclass()&Object::line)
  1531.     {   Lineprim &L=(Lineprim &)P;
  1532.         if (L.checkpoint(P1.x(),P1.y())) P1.valid.set();
  1533.         else P1.valid.clear();
  1534.         if (L.checkpoint(P2.x(),P2.y())) P2.valid.set();
  1535.         else P2.valid.clear();
  1536.     }
  1537.     else
  1538.     {    P1.valid.set();
  1539.         P2.valid.set();
  1540.     }
  1541. }
  1542.  
  1543. int Circle::project (double &x, double &y)
  1544. {    double vx=x-P1->x(),vy=y-P1->y(),r;
  1545.     r=sqrt(vx*vx+vy*vy);
  1546.     if (r<1e-15) return 0;
  1547.     x=P1->x()+vx/r*R; y=P1->y()+vy/r*R;
  1548.     return 1;
  1549. }
  1550.  
  1551. TwoPointAction<Circle> circleaction(11,12);
  1552.  
  1553. void Circle::edit ()
  1554. {   Dialog d(window,IDD_CircleEdit,help,2010);
  1555.     StringItem nameitem(IDP_Name,d,name());
  1556.     PointColor coloritem(IDP_Color,d,1,truecolor()+1);
  1557.     CheckItem hideitem(IDP_Hidden,d,ishidden),
  1558.         shownameitem(IDP_ShowName,d,showname);
  1559.     StringItem lineitem(IDP_Line,d,stripnl(write()),512);
  1560.     lineitem.readonly();
  1561.     DoubleItem ritem(IDL_Length,d,R);
  1562.     ritem.readonly();
  1563.     d.carryout();
  1564.     if (d.result()!=DID_OK) return;
  1565.     setname(nameitem);
  1566.     if (strcmp(nameitem,name()))
  1567.         Warning(String(48),String(1),window);
  1568.     setcolor(coloritem.col()-1);
  1569.     ishidden=hideitem;
  1570.     showname=shownameitem;
  1571. }
  1572.  
  1573. // ******** Middle Point ***************
  1574.  
  1575. class Middle : public Pointprim
  1576. {    Pointprim *P1,*P2;
  1577.     public :
  1578.     Middle (Pointprim &p1, Pointprim &p2);
  1579.     virtual void update ();
  1580.     virtual int dep (Object *o[])
  1581.     {    o[0]=P1; o[1]=P2; return 2;
  1582.     }
  1583.     Pointprim *p1 () { return P1; }
  1584.     Pointprim *p2 () { return P2; }
  1585. };
  1586.  
  1587. TwoPointIO<Middle> middleio("middle");
  1588.  
  1589. Count middlecount;
  1590.  
  1591. Middle::Middle (Pointprim &p1, Pointprim &p2)
  1592. {    P1=&p1; P2=&p2;
  1593.     setio(middleio);
  1594.     setname(String(49),middlecount);
  1595.     objectclass(Object::point);
  1596.     update();
  1597. }
  1598.  
  1599. void Middle::update ()
  1600. {   valid.set();
  1601.     if (!P1->valid || !P2->valid)
  1602.     {    valid.clear();
  1603.         return;
  1604.     }
  1605.     set((P1->x()+P2->x())/2,(P1->y()+P2->y())/2);
  1606. }
  1607.  
  1608. TwoPointAction<Middle> middleaction(45,46);
  1609.  
  1610. // ******** Edit Objects ********
  1611.  
  1612. class EditAction : public Action
  1613. {   public :
  1614.     virtual void perform (long c, long r);
  1615.     virtual void inform ();
  1616. } editaction;
  1617.  
  1618. void EditAction::perform (long c, long r)
  1619. {    Object *P;
  1620.     double x=window.x(c),y=window.y(r);
  1621.     if (!objects.select(x,y,P)) return;
  1622.     P->highlight.set(); objects.redraw();
  1623.     P->edit();
  1624.     objects.update(P);
  1625.     P->highlight.clear();
  1626.     objects.redraw();
  1627. }
  1628.  
  1629. void EditAction::inform ()
  1630. {   tools.inform(String(44));
  1631. }
  1632.  
  1633. // ******** Move action ****************
  1634.  
  1635. class MoveAction : public Action
  1636. {   Pointprim *P;
  1637.     public :
  1638.     MoveAction () { P=0; drag.set(); }
  1639.     virtual void dragperform (int type, long x, long y);
  1640.     virtual void inform ();
  1641.     virtual void start ();
  1642.     virtual int finished () { return P==0; }
  1643.     virtual void abort ()
  1644.     {    if (P) { P->highlight.clear(); objects.redraw(); }
  1645.         P=0;
  1646.     }
  1647. } moveaction;
  1648.  
  1649. void MoveAction::start ()
  1650. {    P=0;
  1651. }
  1652.  
  1653. void MoveAction::dragperform (int type, long c, long r)
  1654. {   double x=window.x(c),y=window.y(r);
  1655.     static int moved=0,pickup=0;
  1656.     int count;
  1657.     if (!P) pickup=0;
  1658.     switch(type)
  1659.     {    case button1down :
  1660.         case button2down :
  1661.             moved=0;
  1662.             if (pickup && P) P->highlight.clear();
  1663.             count=objects.select(x,y,(Object * &)P,
  1664.                     Object::moveable,pickup?0:1);
  1665.             if (count<1) break;
  1666.             P->highlight.set(); objects.redraw();
  1667.             tools.inform(String(13));
  1668.             if (count==1)
  1669.             {    window.capture(1);
  1670.                 pickup=0;
  1671.             }
  1672.             else
  1673.             {    pickup=1;
  1674.             }
  1675.             break;
  1676.         case mousemove :
  1677.             if (!P || pickup) break;
  1678.             P->set(x,y);
  1679.             objects.update(P);
  1680.             objects.redraw();
  1681.             moved=1;
  1682.             break;
  1683.         case button1up :
  1684.         case button2up :
  1685.             if (pickup) break;
  1686.             if (P)
  1687.             {    window.capture(0);
  1688.                 P->highlight.clear();
  1689.                 objects.redraw();
  1690.             }
  1691.             if (!moved && type==button2up)
  1692.             {    editaction.perform(c,r);
  1693.             }
  1694.             inform();
  1695.             P=0;
  1696.             break;
  1697.     }
  1698. }
  1699.  
  1700. void MoveAction::inform ()
  1701. {    tools.inform(String(14));
  1702. }
  1703.  
  1704. // ******** Move on Object action ****************
  1705.  
  1706. class MoveonAction : public Action
  1707. {   Pointprim *P;
  1708.     Object *O;
  1709.     public :
  1710.     MoveonAction () { drag.clear(); }
  1711.     virtual void dragperform (int type, long c, long r);
  1712.     virtual void perform (long c, long r);
  1713.     virtual void inform ();
  1714.     virtual void start ();
  1715.     virtual void abort ();
  1716. } moveonaction;
  1717.  
  1718. void MoveonAction::start ()
  1719. {   P=0;
  1720.     drag.clear();
  1721. }
  1722.  
  1723. void MoveonAction::dragperform (int type, long c, long r)
  1724. {   double x=window.x(c),y=window.y(r);
  1725.     switch(type)
  1726.     {    case button1down :
  1727.             if (!objects.select(x,y,(Object * &)P,
  1728.                     Object::moveable,0))
  1729.                 break;
  1730.             objects.mark(P);
  1731.             if (O->mark)
  1732.             {    P=0; break;
  1733.             }
  1734.             P->highlight.set(); objects.redraw();
  1735.             tools.inform(String(13));
  1736.             break;
  1737.         case mousemove :
  1738.             if (!P) break;
  1739.             if (O->project(x,y))
  1740.             {    P->set(x,y);
  1741.                 P->update();
  1742.             }
  1743.             objects.update(P);
  1744.             objects.redraw();
  1745.             break;
  1746.         case button1up :
  1747.             if (!P) break;
  1748.             P->highlight.clear(); P=0;
  1749.             O->highlight.clear();
  1750.             drag.clear();
  1751.             objects.redraw();
  1752.             inform();
  1753.             break;
  1754.     }
  1755. }
  1756.  
  1757. void MoveonAction::perform (long c, long r)
  1758. {   double x=window.x(c),y=window.y(r);
  1759.     if (!objects.select(x,y,O,Object::line|Object::circle))
  1760.         return;
  1761.     O->highlight.set();
  1762.     objects.redraw();
  1763.     drag.set();
  1764.     inform();
  1765. }
  1766.  
  1767. void MoveonAction::abort ()
  1768. {   if (drag) O->highlight.clear();
  1769.     drag.clear();
  1770.     objects.redraw();
  1771. }
  1772.  
  1773. void MoveonAction::inform ()
  1774. {    if (!drag) tools.inform(String(37));
  1775.     else tools.inform(String(14));
  1776. }
  1777.  
  1778. // ******* Intersections ***************
  1779.  
  1780. class OtherIntersection; // Intersections may generate two points
  1781. class Intersection : public Pointprim
  1782. // Intersection of line/circle with line/circle
  1783. {    Object *P1,*P2;
  1784.     OtherIntersection *Other; // NULL or other point
  1785.     public :
  1786.     Intersection (Object &p1, Object &p2);
  1787.     virtual void update ();
  1788.     virtual int dep (Object *o[])
  1789.     {    o[0]=P1; o[1]=P2; return 2;
  1790.     }
  1791.     Object *first () { return P1; }
  1792.     Object *second () { return P2; }
  1793.     OtherIntersection *other() { return Other; }
  1794. };
  1795.  
  1796. class OtherIntersection : public Pointprim
  1797. // The other intersection point
  1798. {    Intersection *Other; // knows its brother
  1799.     public :
  1800.     OtherIntersection (Intersection *other);
  1801.     virtual int dep (Object *o[])
  1802.     {    o[0]=Other; return 1;
  1803.     }
  1804.     Intersection *other () { return Other; }
  1805.     virtual Object *original () { return Other; }
  1806. };
  1807.  
  1808. class NoIO : public IO
  1809.     // class does not appear in files
  1810. {    public :
  1811.     NoIO () : IO("otherintersection") {}
  1812.     virtual char *write (Object &o) { return ""; }
  1813. } noio;
  1814.  
  1815. Count iscount;
  1816.  
  1817. OtherIntersection::OtherIntersection (Intersection *other)
  1818. {    Other=other;
  1819.     objectclass(Object::point);
  1820.     setname(String(15),iscount);
  1821.     setio(noio);
  1822. }
  1823.  
  1824. class IntersectionIO : public IO
  1825. {    public :
  1826.     IntersectionIO () : IO("intersection") {}
  1827.     virtual void depwrite (Object &o)
  1828.     {    Intersection &l=(Intersection &)o;
  1829.         depadd(*l.first()); comma(); depadd(*l.second());
  1830.     }
  1831.     virtual void reswrite (Object &o)
  1832.     {   Intersection &l=(Intersection &)o;
  1833.         if (l.other()) { comma(); resadd(*l.other()); }
  1834.     }
  1835.     virtual int interpret (Input &i);
  1836. } intersectionio;
  1837.  
  1838. int IntersectionIO::interpret (Input &i)
  1839. {   Intersection *l;
  1840.     if (i.nright()!=2) return 0;
  1841.     if (i.nleft()==1)
  1842.     {    Object *o1=i.object(0,Object::line),
  1843.                 *o2=i.object(1,Object::line);
  1844.         if (!o1 || !o2) return 0;
  1845.         l=new Intersection(*o1,*o2);
  1846.         return i.set(*l,0);
  1847.     }
  1848.     else if (i.nleft()==2)
  1849.     {    Object *o1=i.object(0,Object::line|Object::circle),
  1850.                 *o2=i.object(1,Object::line|Object::circle);
  1851.         if (!o1 || !o2) return 0;
  1852.         l=new Intersection(*o1,*o2);
  1853.         if (!l->other()) return 0;
  1854.         if (!i.set(*l,0)) return 0;
  1855.         return i.set(*l->other(),1);
  1856.     }
  1857.     return 0;
  1858. }
  1859.  
  1860. Intersection::Intersection (Object &p1, Object &p2) : Pointprim()
  1861. {    P1=&p1; P2=&p2;
  1862.     if ((P1->objectclass()&Object::circle) ||
  1863.         (P2->objectclass()&Object::circle))
  1864.             Other=new OtherIntersection(this);
  1865.     else Other=0;
  1866.     objectclass(Object::point);
  1867.     setname(String(15),iscount);
  1868.     setio(intersectionio);
  1869.     update();
  1870. }
  1871.  
  1872. void Intersection::update ()
  1873. {   valid.set();
  1874.     if (!P1->valid || !P2->valid)
  1875.     {    valid.clear();
  1876.         if (Other) Other->valid.clear();
  1877.         return;
  1878.     }
  1879.     if (!Other) // Means the intersection is between lines
  1880.         ((Lineprim *)P1)->intersect(*(Lineprim *)P2,
  1881.             *(Pointprim *)this);
  1882.     else if (P1->objectclass()&Object::circle) // first is a circle
  1883.         ((Circle *)P1)->intersect(*P2,
  1884.             *(Pointprim *)this,*(Pointprim *)Other);
  1885.     else // second must be a circle
  1886.         ((Circle *)P2)->intersect(*P1,
  1887.             *(Pointprim *)this,*(Pointprim *)Other);
  1888. }
  1889.  
  1890. class IntersectionAction : public Action // generate a line
  1891. {   int State;
  1892.     Object *P1,*P2;
  1893.     public :
  1894.     virtual void perform (long x, long y);
  1895.     virtual void inform ();
  1896.     virtual void start ();
  1897.     virtual void abort ();
  1898.     virtual int finished () { return State==1; }
  1899. } intersectionaction;
  1900.  
  1901. void IntersectionAction::start ()
  1902. {    State=1;
  1903. }
  1904.  
  1905. void IntersectionAction::inform ()
  1906. {    switch (State)
  1907.     {    case 1 : tools.inform(String(16)); break;
  1908.         case 2 : tools.inform(String(17)); break;
  1909.     }
  1910. }
  1911.  
  1912. void IntersectionAction::perform (long c, long r)
  1913. {    double x=window.x(c),y=window.y(r);
  1914.     switch (State)
  1915.     {    case 1 :
  1916.             if (!objects.select(x,y,P1,
  1917.                 Object::line|Object::circle)) return;
  1918.             P1->highlight.set(); objects.redraw();
  1919.             State=2; break;
  1920.         case 2 :
  1921.             if (!objects.select(x,y,P2,
  1922.                 Object::line|Object::circle)) return;
  1923.             if (P1==P2) return;
  1924.             State=1;
  1925.             P1->highlight.clear();
  1926.             new Intersection(*P1,*P2);
  1927.             objects.redraw();
  1928.             break;
  1929.     }
  1930.     inform();
  1931. }
  1932.  
  1933. void IntersectionAction::abort ()
  1934. {   if (State==2)
  1935.     {    P1->highlight.clear(); objects.redraw();
  1936.     }
  1937.     State=0;
  1938. }
  1939.  
  1940. // ******** Hide/Unhide Objects ********
  1941.  
  1942. class HideAction : public Action
  1943. {   public :
  1944.     virtual void perform (long c, long r);
  1945.     virtual void inform ();
  1946. } hideaction;
  1947.  
  1948. void HideAction::perform (long c, long r)
  1949. {    Object *P;
  1950.     double x=window.x(c),y=window.y(r);
  1951.     if (!objects.select(x,y,P)) return;
  1952.     P->ishidden.toggle();
  1953.     objects.redraw();
  1954. }
  1955.  
  1956. void HideAction::inform ()
  1957. {   tools.inform(String(18));
  1958. }
  1959.  
  1960. // ******* Delete Action ***************
  1961.  
  1962. class DeleteAction : public Action
  1963. {    public :
  1964.     virtual void perform (long c, long r);
  1965.     virtual void inform ();
  1966. } deleteaction;
  1967.  
  1968. void DeleteAction::perform (long c, long r)
  1969. {    Object *P;
  1970.     double x=window.x(c),y=window.y(r);
  1971.     if (!objects.select(x,y,P)) return;
  1972.     objects.clear(P->original());
  1973.     objects.redraw();
  1974. }
  1975.  
  1976. void DeleteAction::inform ()
  1977. {    tools.inform(String(23));
  1978. }
  1979.  
  1980. // ******** Parallels **************
  1981.  
  1982. class DepLine : public Line
  1983.     // A line with no IO
  1984. {   Object *O;
  1985.     public :
  1986.     DepLine(Pointprim &p1, Pointprim &p2) :
  1987.         Line(p1,p2),O(&p2)
  1988.     {    setio(noio);
  1989.     }
  1990.     virtual Object *original () { return O; }
  1991. };
  1992.  
  1993. class Parallel : public Pointprim
  1994.     // a line parallel to another line
  1995.     // passing through a given point
  1996.     // creates a new point and a line
  1997. {   protected :
  1998.     Pointprim *P;
  1999.     Lineprim *L;
  2000.     DepLine *Other;
  2001.     public :
  2002.     Parallel (Pointprim &p, Lineprim &l);
  2003.     virtual void update ();
  2004.     virtual int dep (Object *o[])
  2005.     {    o[0]=P; o[1]=L; return 2;
  2006.     }
  2007.     Pointprim *point () { return P; }
  2008.     Lineprim *line () { return L; }
  2009.     DepLine *other () { return Other; }
  2010.     void other (DepLine *o) { Other=o; }
  2011. };
  2012.  
  2013. template<class Class>
  2014. class PointLineIO : public IO
  2015. {    public :
  2016.     PointLineIO (char *name) : IO(name) {}
  2017.     virtual void depwrite (Object &o)
  2018.     {    Class &l=(Class &)o;
  2019.         depadd(*l.point()); comma(); depadd(*l.line());
  2020.     }
  2021.     virtual void reswrite (Object &o)
  2022.     {   Class &l=(Class &)o;
  2023.         comma(); resadd(*l.other());
  2024.     }
  2025.     virtual int interpret (Input &i);
  2026. };
  2027.  
  2028. template<class Class> int PointLineIO<Class>::interpret (Input &i)
  2029. {    if (i.nleft()!=2 || i.nright()!=2) return 0;
  2030.     Pointprim *p=(Pointprim *)i.object(0,Object::point);
  2031.     Lineprim *l=(Lineprim *)i.object(1,Object::line);
  2032.     if (!p || !l) return 0;
  2033.     Class *pl=new Class(*p,*l);
  2034.     pl->other(new DepLine(*p,*pl));
  2035.     if (!i.set(*pl,0)) return 0;
  2036.     return i.set(*pl->other(),1);
  2037. }
  2038.  
  2039. PointLineIO<Parallel> parallelio("parallel");
  2040.  
  2041. Parallel::Parallel (Pointprim &p, Lineprim &l) : Pointprim()
  2042. {    P=&p; L=&l;
  2043.     objectclass(Object::point);
  2044.     setio(parallelio);
  2045.     update();
  2046. }
  2047.  
  2048. void Parallel::update ()
  2049. {   valid.set();
  2050.     if (!P->valid || !L->valid)
  2051.     {    valid.clear(); return;
  2052.     }
  2053.     set(P->x()+L->vx(),P->y()+L->vy());
  2054. }
  2055.  
  2056. template<class Class>
  2057. class PointLineAction : public Action // generate a parallel
  2058. {   protected :
  2059.     int State,I1,I2;
  2060.     Pointprim *P;
  2061.     Lineprim *L;
  2062.     public :
  2063.     PointLineAction (int i1, int i2) : I1(i1),I2(i2) {}
  2064.     virtual void perform (long x, long y);
  2065.     virtual void inform ();
  2066.     virtual void start ();
  2067.     virtual void abort ();
  2068.     virtual int finished () { return State==1; }
  2069. };
  2070.  
  2071. PointLineAction<Parallel> parallelaction(30,31);
  2072.  
  2073. template<class Class> void PointLineAction<Class>::start ()
  2074. {    State=1;
  2075. }
  2076.  
  2077. template<class Class> void PointLineAction<Class>::inform ()
  2078. {    switch (State)
  2079.     {    case 1 : tools.inform(String(I1)); break;
  2080.         case 2 : tools.inform(String(I2)); break;
  2081.     }
  2082. }
  2083.  
  2084. template<class Class>
  2085.     void PointLineAction<Class>::perform (long c, long r)
  2086. {   Class *R;
  2087.     double x=window.x(c),y=window.y(r);
  2088.     switch (State)
  2089.     {    case 1 :
  2090.             if (!objects.select(x,y,(Object *&)L,Object::line))
  2091.                 return;
  2092.             L->highlight.set(); objects.redraw();
  2093.             State=2; break;
  2094.         case 2 :
  2095.             if (!objects.select(x,y,(Object *&)P,Object::point))
  2096.                 return;
  2097.             State=1;
  2098.             L->highlight.clear();
  2099.             R=new Class(*P,*L);
  2100.             R->ishidden.set();
  2101.             R->other(new DepLine(*P,*R));
  2102.             objects.redraw();
  2103.             break;
  2104.     }
  2105.     inform();
  2106. }
  2107.  
  2108. template<class Class> void PointLineAction<Class>::abort ()
  2109. {   if (State==2)
  2110.     {    L->highlight.clear(); objects.redraw();
  2111.     }
  2112.     State=0;
  2113. }
  2114.  
  2115. // ******** Rectangular Action **************
  2116.  
  2117. class Rectangular : public Pointprim
  2118.     // a line parallel to another line
  2119.     // passing through a given point
  2120.     // creates a new point and a line
  2121. {   protected :
  2122.     Pointprim *P;
  2123.     Lineprim *L;
  2124.     DepLine *Other;
  2125.     public :
  2126.     Rectangular (Pointprim &p, Lineprim &l);
  2127.     virtual void update ();
  2128.     virtual int dep (Object *o[])
  2129.     {    o[0]=P; o[1]=L; return 2;
  2130.     }
  2131.     Pointprim *point () { return P; }
  2132.     Lineprim *line () { return L; }
  2133.     DepLine *other () { return Other; }
  2134.     void other (DepLine *o) { Other=o; }
  2135. };
  2136.  
  2137. PointLineIO<Rectangular> rectangulario("rectangular");
  2138.  
  2139. Rectangular::Rectangular (Pointprim &p, Lineprim &l) :
  2140.         Pointprim()
  2141. {    P=&p; L=&l;
  2142.     objectclass(Object::point);
  2143.     setio(rectangulario);
  2144.     update();
  2145. }
  2146.  
  2147. void Rectangular::update ()
  2148. {   valid.set();
  2149.     if (!P->valid || !L->valid)
  2150.     {    valid.clear(); return;
  2151.     }
  2152.     set(P->x()-L->vy(),P->y()+L->vx());
  2153. }
  2154.  
  2155. PointLineAction<Rectangular> rectangularaction(32,33);
  2156.  
  2157. // ******** Point on Object **************
  2158.  
  2159. class Pointon : public Pointprim
  2160.     // A Point on a Line or Circle
  2161. {   protected :
  2162.     Object *O;
  2163.     public :
  2164.     Pointon (Object &O);
  2165.     Pointon (Object &O, double x, double y);
  2166.     virtual void update ();
  2167.     virtual int dep (Object *o[])
  2168.     {    o[0]=O; return 1;
  2169.     }
  2170.     Object *object() { return O; }
  2171. };
  2172.  
  2173. class PointonIO : public IO
  2174. {    public :
  2175.     PointonIO () : IO("pointon") {}
  2176.     virtual void depwrite (Object &o)
  2177.     {    Pointon &p=(Pointon &)o;
  2178.         depadd(*p.object());
  2179.         sprintf(end(),",%g,%g",p.x(),p.y());
  2180.     }
  2181.     virtual int interpret (Input &i);
  2182. } pointonio;
  2183.  
  2184. int PointonIO::interpret (Input &i)
  2185. {    if (i.nleft()!=1 || i.nright()!=3) return 0;
  2186.     Object *o=i.object(0,Object::line|Object::circle);
  2187.     if (!o) return 0;
  2188.     double x,y;
  2189.     if (!i.right()[1].todouble(x) || !i.right()[2].todouble(y))
  2190.         return 0;
  2191.     Pointon *P=new Pointon(*o,x,y);
  2192.     return i.set(*P,0);
  2193. }
  2194.  
  2195. Count pointoncount;
  2196.  
  2197. Pointon::Pointon (Object &o) : Pointprim()
  2198. {    O=&o;
  2199.     objectclass(Object::point|Object::moveable);
  2200.     setname(String(50),pointoncount);
  2201.     setio(pointonio);
  2202.     update();
  2203. }
  2204.  
  2205. Pointon::Pointon (Object &o, double x, double y)
  2206. {    O=&o;
  2207.     objectclass(Object::point|Object::moveable);
  2208.     setname(String(50),pointoncount);
  2209.     setio(pointonio);
  2210.     set(x,y);
  2211.     update();
  2212. }
  2213.  
  2214. void Pointon::update ()
  2215. {   double a=x(),b=y();
  2216.     valid.set();
  2217.     if (!O->valid)
  2218.     {    valid.clear(); return;
  2219.     }
  2220.     if (O->project(a,b)) set(a,b);
  2221. }
  2222.  
  2223. class PointonAction : public Action // generate a parallel
  2224. {   Object *O;
  2225.     protected :
  2226.     public :
  2227.     virtual void perform (long x, long y);
  2228.     virtual void inform ();
  2229. } pointonaction;
  2230.  
  2231. void PointonAction::inform ()
  2232. {    tools.inform(String(38));
  2233. }
  2234.  
  2235. void PointonAction::perform (long c, long r)
  2236. {   double x=window.x(c),y=window.y(r);
  2237.     if (!objects.select(x,y,O,Object::line|Object::circle))
  2238.         return;
  2239.     new Pointon(*O,x,y);
  2240.     objects.redraw();
  2241. }
  2242.  
  2243. // ******** Circles of three points **************
  2244.  
  2245. class Circle3Circle : public Circle
  2246. {   Object *O;
  2247.     public :
  2248.     Circle3Circle (Pointprim &p1, Pointprim &p2) :
  2249.         Circle(p1,p2),O(&p2)
  2250.     {    setio(noio);
  2251.     }
  2252.     virtual Object *original () { return O; }
  2253. };
  2254.  
  2255. class Circle3 : public Pointprim
  2256.     // Create a circle from midpoint and radius
  2257. {   protected :
  2258.     Pointprim *P1,*P2,*M;
  2259.     Circle3Circle *C;
  2260.     public :
  2261.     Circle3 (Pointprim &m, Pointprim &p1, Pointprim &p2);
  2262.     virtual void update ();
  2263.     virtual int dep (Object *o[])
  2264.     {    o[0]=P1; o[1]=P2; o[2]=M; return 3;
  2265.     }
  2266.     Pointprim *p1 () { return P1; }
  2267.     Pointprim *p2 () { return P2; }
  2268.     Pointprim *m () { return M; }
  2269.     Circle3Circle *c () { return C; }
  2270.     void c (Circle3Circle *cc) { C=cc; }
  2271. };
  2272.  
  2273. class Circle3IO : public IO
  2274. {    public :
  2275.     Circle3IO () : IO("circle3") {}
  2276.     virtual void depwrite (Object &o)
  2277.     {    Circle3 &l=(Circle3 &)o;
  2278.         depadd(*l.m()); comma();
  2279.         depadd(*l.p1()); comma(); depadd(*l.p2());
  2280.     }
  2281.     virtual void reswrite (Object &o)
  2282.     {   Circle3 &l=(Circle3 &)o;
  2283.         comma(); resadd(*l.c());
  2284.     }
  2285.     virtual int interpret (Input &i);
  2286. } circle3io;
  2287.  
  2288. int Circle3IO::interpret (Input &i)
  2289. {    if (i.nleft()!=2 || i.nright()!=3) return 0;
  2290.     Pointprim *p1=(Pointprim *)i.object(0,Object::point),
  2291.         *p2=(Pointprim *)i.object(1,Object::point),
  2292.         *p3=(Pointprim *)i.object(2,Object::point);
  2293.     if (!p1 || !p2 || !p3) return 0;
  2294.     Circle3 *l=new Circle3(*p1,*p2,*p3);
  2295.     l->c(new Circle3Circle(*p1,*l));
  2296.     if (!i.set(*l,0)) return 0;
  2297.     return i.set(*l->c(),1);
  2298. }
  2299.  
  2300. Circle3::Circle3 (Pointprim &m, Pointprim &p1, Pointprim &p2) : Pointprim()
  2301. {    P1=&p1; P2=&p2; M=&m;
  2302.     objectclass(Object::point);
  2303.     setio(circle3io);
  2304.     update();
  2305. }
  2306.  
  2307. void Circle3::update ()
  2308. {   valid.set();
  2309.     if (!P1->valid || !P2->valid || !M->valid)
  2310.     {    valid.clear(); return;
  2311.     }
  2312.     set(M->x()+P2->x()-P1->x(),M->y()+P2->y()-P1->y());
  2313. }
  2314.  
  2315. class Circle3Action : public Action // generate a parallel
  2316. {   protected :
  2317.     int State;
  2318.     Pointprim *P1,*P2,*M;
  2319.     public :
  2320.     virtual void perform (long x, long y);
  2321.     virtual void inform ();
  2322.     virtual void start ();
  2323.     virtual void abort ();
  2324.     virtual int finished () { return State==1; }
  2325. } circle3action;
  2326.  
  2327. void Circle3Action::start ()
  2328. {    State=1;
  2329. }
  2330.  
  2331. void Circle3Action::inform ()
  2332. {    switch (State)
  2333.     {    case 1 : tools.inform(String(34)); break;
  2334.         case 2 : tools.inform(String(35)); break;
  2335.         case 3 : tools.inform(String(36)); break;
  2336.     }
  2337. }
  2338.  
  2339. void Circle3Action::perform (long c, long r)
  2340. {   Circle3 *R;
  2341.     double x=window.x(c),y=window.y(r);
  2342.     switch (State)
  2343.     {    case 1 :
  2344.             if (!objects.select(x,y,(Object *&)M,Object::point))
  2345.                 return;
  2346.             M->highlight.set(); objects.redraw();
  2347.             State=2; break;
  2348.         case 2 :
  2349.             if (!objects.select(x,y,(Object *&)P1,Object::point))
  2350.                 return;
  2351.             P1->highlight.set(); objects.redraw();
  2352.             State=3; break;
  2353.         case 3 :
  2354.             if (!objects.select(x,y,(Object *&)P2,Object::point))
  2355.                 return;
  2356.             State=1;
  2357.             M->highlight.clear();
  2358.             P1->highlight.clear();
  2359.             R=new Circle3(*M,*P1,*P2);
  2360.             R->ishidden.set();
  2361.             R->c(new Circle3Circle(*M,*R));
  2362.             objects.redraw();
  2363.             break;
  2364.     }
  2365.     inform();
  2366. }
  2367.  
  2368. void Circle3Action::abort ()
  2369. {   if (State==2)
  2370.     {    M->highlight.clear();
  2371.         objects.redraw();
  2372.     }
  2373.     else if (State==3)
  2374.     {    M->highlight.clear();
  2375.         P1->highlight.clear();
  2376.         objects.redraw();
  2377.     }
  2378.     State=0;
  2379. }
  2380.  
  2381. // ******** Angles of three points **************
  2382.  
  2383. class Angle : public Object
  2384.     // Create a circle from midpoint and radius
  2385. {   protected :
  2386.     Pointprim *P1,*P2,*M;
  2387.     double Phi1,Phi2;
  2388.     public :
  2389.     Angle (Pointprim &m, Pointprim &p1, Pointprim &p2);
  2390.     virtual void update ();
  2391.     virtual int dep (Object *o[])
  2392.     {    o[0]=P1; o[1]=P2; o[2]=M; return 3;
  2393.     }
  2394.     Pointprim *p1 () { return P1; }
  2395.     Pointprim *p2 () { return P2; }
  2396.     Pointprim *m () { return M; }
  2397.     virtual void draw (PS &ps);
  2398.     virtual double distance (double x, double y)
  2399.     {    return M->distance(x,y);
  2400.     }
  2401.     virtual void edit ();
  2402. };
  2403.  
  2404. class AngleIO : public IO
  2405. {    public :
  2406.     AngleIO () : IO("angle") {}
  2407.     virtual void depwrite (Object &o)
  2408.     {    Angle &l=(Angle &)o;
  2409.         depadd(*l.p1()); comma();
  2410.         depadd(*l.m()); comma(); depadd(*l.p2());
  2411.     }
  2412.     virtual int interpret (Input &i);
  2413. } angleio;
  2414.  
  2415. int AngleIO::interpret (Input &i)
  2416. {    if (i.nleft()!=1 || i.nright()!=3) return 0;
  2417.     Pointprim *p1=(Pointprim *)i.object(0,Object::point),
  2418.         *p2=(Pointprim *)i.object(1,Object::point),
  2419.         *p3=(Pointprim *)i.object(2,Object::point);
  2420.     if (!p1 || !p2 || !p3) return 0;
  2421.     Angle *l=new Angle(*p1,*p2,*p3);
  2422.     return i.set(*l,0);
  2423. }
  2424.  
  2425. Count anglecount;
  2426.  
  2427. Angle::Angle (Pointprim &p1, Pointprim &m, Pointprim &p2)
  2428. {    P1=&p1; P2=&p2; M=&m;
  2429.     objectclass(Object::angle);
  2430.     setio(angleio);
  2431.     setname(String(56),anglecount);
  2432.     update();
  2433. }
  2434.  
  2435. int arg (double vx, double vy, double &phi)
  2436. {    if (fabs(vx)<1e-15 && fabs(vy)<1e-15) return 0;
  2437.     phi=atan2(vy,vx);
  2438.     return 1;
  2439. }
  2440.  
  2441. const double pideg=180.0/(4*atan(1)),pi2=8*atan(1);
  2442.  
  2443. void Angle::update ()
  2444. {    if (!P1->valid || !P2->valid || !M->valid)
  2445.     {    valid.clear(); return;
  2446.     }
  2447.     valid.set();
  2448.     if (!arg(P1->x()-M->x(),P1->y()-M->y(),Phi1)) valid.clear();
  2449.     if (!arg(P2->x()-M->x(),P2->y()-M->y(),Phi2)) valid.clear();
  2450. }
  2451.  
  2452. void Angle::draw (PS &ps)
  2453. {   long c;
  2454.     double x,y,h,phi1,phi2;
  2455.     if (!valid || hidden()) return;
  2456.     ps.arc(window.col(M->x()),window.row(M->y()),20,
  2457.         1,Phi1*pideg,Phi2*pideg,color());
  2458. }
  2459.  
  2460. class AngleAction : public Action // generate a parallel
  2461. {   protected :
  2462.     int State;
  2463.     Pointprim *P1,*P2,*M;
  2464.     public :
  2465.     virtual void perform (long x, long y);
  2466.     virtual void inform ();
  2467.     virtual void start ();
  2468.     virtual void abort ();
  2469.     virtual int finished () { return State==1; }
  2470. } angleaction;
  2471.  
  2472. void AngleAction::start ()
  2473. {    State=1;
  2474. }
  2475.  
  2476. void AngleAction::inform ()
  2477. {    switch (State)
  2478.     {    case 1 : tools.inform(String(53)); break;
  2479.         case 2 : tools.inform(String(54)); break;
  2480.         case 3 : tools.inform(String(55)); break;
  2481.     }
  2482. }
  2483.  
  2484. void AngleAction::perform (long c, long r)
  2485. {   double x=window.x(c),y=window.y(r);
  2486.     switch (State)
  2487.     {    case 1 :
  2488.             if (!objects.select(x,y,(Object *&)P1,Object::point))
  2489.                 return;
  2490.             P1->highlight.set(); objects.redraw();
  2491.             State=2; break;
  2492.         case 2 :
  2493.             if (!objects.select(x,y,(Object *&)M,Object::point))
  2494.                 return;
  2495.             M->highlight.set(); objects.redraw();
  2496.             State=3; break;
  2497.         case 3 :
  2498.             if (!objects.select(x,y,(Object *&)P2,Object::point))
  2499.                 return;
  2500.             State=1;
  2501.             P1->highlight.clear();
  2502.             M->highlight.clear();
  2503.             new Angle(*P1,*M,*P2);
  2504.             objects.redraw();
  2505.             break;
  2506.     }
  2507.     inform();
  2508. }
  2509.  
  2510. void AngleAction::abort ()
  2511. {   if (State==2)
  2512.     {    P1->highlight.clear();
  2513.         objects.redraw();
  2514.     }
  2515.     else if (State==3)
  2516.     {    M->highlight.clear();
  2517.         P1->highlight.clear();
  2518.         objects.redraw();
  2519.     }
  2520.     State=0;
  2521. }
  2522.  
  2523. void Angle::edit ()
  2524. {   Dialog d(window,IDD_AngleEdit,help,2010);
  2525.     StringItem nameitem(IDP_Name,d,name());
  2526.     PointColor coloritem(IDP_Color,d,1,truecolor()+1);
  2527.     CheckItem hideitem(IDP_Hidden,d,ishidden),
  2528.         shownameitem(IDP_ShowName,d,showname);
  2529.     StringItem lineitem(IDP_Line,d,stripnl(write()),512);
  2530.     lineitem.readonly();
  2531.     DoubleItem ritem(IDL_Length,d,
  2532.         fabs(fmod((Phi2-Phi1)*pideg+360,360)));
  2533.     ritem.readonly();
  2534.     d.carryout();
  2535.     if (d.result()!=DID_OK) return;
  2536.     setname(nameitem);
  2537.     if (strcmp(nameitem,name()))
  2538.         Warning(String(48),String(1),window);
  2539.     setcolor(coloritem.col()-1);
  2540.     ishidden=hideitem;
  2541.     showname=shownameitem;
  2542. }
  2543.  
  2544. // ********* Track action **************
  2545.  
  2546. class TrackAction : public Action
  2547. {   Pointprim *P;
  2548.     public :
  2549.     virtual void inform ();
  2550.     virtual void perform (long c, long r);
  2551. } trackaction;
  2552.  
  2553. void TrackAction::inform ()
  2554. {    tools.inform(String(39));
  2555. }
  2556.  
  2557. void TrackAction::perform (long c, long r)
  2558. {    double x=window.x(c),y=window.y(r);
  2559.     if (!objects.select(x,y,(Object * &)P,Object::point))
  2560.         return;
  2561.     P->starttrack();
  2562.     objects.redraw();
  2563. }
  2564.  
  2565. // *********** Makro things ********
  2566.  
  2567. class ParameterList
  2568. // List for holding parameter and target objects
  2569. {    Object *P;
  2570.     ParameterList *Next;
  2571.     String Prompt,Name; // Parameter prompt and name in makro
  2572.     int Class; // point, line or circle
  2573.     public :
  2574.     ParameterList (Object &p, char *s="", char *sn="") :
  2575.         P(&p),Next(0),Prompt(s),Name(sn) {}
  2576.     ~ParameterList ()
  2577.     {    if (Next) delete Next;
  2578.     }
  2579.     ParameterList (char *n, char *s, int c) :
  2580.         P(0),Next(0),Prompt(s),Name(n),Class(c) {}
  2581.     ParameterList * next () { return Next; }
  2582.     void next (ParameterList &p) { Next=&p; }
  2583.     void append (ParameterList *p);
  2584.     Object *object () { return P; }
  2585.     void object (Object *o) { P=o; }
  2586.     char * prompt () { return Prompt; }
  2587.     void prompt (char *s) { Prompt.copy(s); }
  2588.     char * name () { return Name; }
  2589.     void name (char *s) { Name.copy(s); }
  2590.     int objectclass () { return Class; }
  2591.     void objectclass (int t) { Class=t; }
  2592. };
  2593.  
  2594. void ParameterList::append (ParameterList *p)
  2595. {    if (!Next) Next=p;
  2596.     else Next->append(p);
  2597. }
  2598.  
  2599. class Makro;
  2600. class MakroDefineAction : public Action
  2601. // Action to define a makro by choosing parameters first,
  2602. // then targets
  2603. {   ParameterList *P,*T;
  2604.     int State;
  2605.     public :
  2606.     MakroDefineAction () : P(0),T(0),State(0) {}
  2607.     virtual void inform ();
  2608.     virtual void start ();
  2609.     virtual void abort ();
  2610.     virtual void perform (long c, long r);
  2611.     void unhighlight ();
  2612.     void forget ();
  2613.     void tforget ();
  2614.     int state () { return State; }
  2615.     ParameterList * parameter () { return P; }
  2616.     void advance ();
  2617.     int invalid () { return P==0 || T==0; }
  2618.     int rektest (Object *o);
  2619.     int testmakro ();
  2620.         // test if everything is constructable
  2621.         // and mark construction steps
  2622.     int testmakro (Object *o);
  2623.         // test if o is constructable
  2624.     int isparam (Object *o); // check if o is one of the parameters
  2625.     void createmakro (char *name);
  2626.     void createmakro (Makro *m);
  2627. } makrodefineaction;
  2628.  
  2629. void MakroDefineAction::forget ()
  2630. {    if (P) delete P;
  2631.     if (T) delete T;
  2632.     P=T=0;
  2633. }
  2634.  
  2635. void MakroDefineAction::tforget ()
  2636. {    if (T) delete T;
  2637.     T=0;
  2638. }
  2639.  
  2640. void MakroDefineAction::unhighlight ()
  2641. {    ParameterList *p;
  2642.     p=P;
  2643.     while (p)
  2644.     {    p->object()->highlight.clear();
  2645.         p=p->next();
  2646.     }
  2647.     p=T;
  2648.     while (p)
  2649.     {    p->object()->highlight.clear();
  2650.         p=p->next();
  2651.     }
  2652.     objects.redraw();
  2653. }
  2654.  
  2655. void MakroDefineAction::start ()
  2656. {    forget(); State=1;
  2657. }
  2658.  
  2659. void MakroDefineAction::abort ()
  2660. {    unhighlight();
  2661.     forget();
  2662.     State=0;
  2663. }
  2664.  
  2665. void MakroDefineAction::inform ()
  2666. {    if (State==2) tools.inform(String(61));
  2667.     else tools.inform(String(60));
  2668. }
  2669.  
  2670. void MakroDefineAction::advance ()
  2671. {    unhighlight(); State=2; inform();
  2672. }
  2673.  
  2674. void MakroDefineAction::perform (long c, long r)
  2675. {    double x=window.x(c),y=window.y(r);
  2676.     Object *o;
  2677.     if (!objects.select
  2678.         (x,y,o,
  2679.         Object::point|Object::line|Object::circle,1,0))
  2680.         return;
  2681.     if (State==1)
  2682.     {   int np;
  2683.         Dialog d(window,IDD_Parameter,help,2070);
  2684.         if (o->objectclass()&Object::circle) np=65;
  2685.         else if (o->objectclass()&Object::line) np=64;
  2686.         else np=63;
  2687.         StringItem prompt(ID_Parameter,d,String(np));
  2688.         d.carryout();
  2689.         if (d.result()!=Dialog::ok) return;
  2690.         String n(prompt);
  2691.         if (!*(char *)n) n.copy(String(69));
  2692.         ParameterList *pl=new ParameterList(*o,n);
  2693.         if (P) P->append(pl);
  2694.         else P=pl;
  2695.     }
  2696.     else if (State==2)
  2697.     {   if (isparam(o))
  2698.         {    Warning(String(68),String(1),window);
  2699.             return;
  2700.         }
  2701.         if (!makrodefineaction.testmakro(o)) return;
  2702.         ParameterList *tl=new ParameterList(*o,"");
  2703.         if (T) T->append(tl);
  2704.         else T=tl;
  2705.     }
  2706.     o->highlight.set(); objects.redraw();
  2707. }
  2708.  
  2709. int MakroDefineAction::isparam (Object *o)
  2710. {    ParameterList *ol=P;
  2711.     while (ol)
  2712.     {    if (ol->object()==o) return 1;
  2713.         ol=ol->next();
  2714.     }
  2715.     return 0;
  2716. }
  2717.  
  2718. void domakroparameter ()
  2719. // menu: Choose Parameters
  2720. {    if (makrodefineaction.state()==2) makrodefineaction.abort();
  2721.     window.action(makrodefineaction);
  2722. }
  2723.  
  2724. void domakroconstructed ()
  2725. // menu: Choose Targets
  2726. {    if (makrodefineaction.state()==2)
  2727.     {   makrodefineaction.unhighlight();
  2728.         makrodefineaction.tforget();
  2729.     }
  2730.     else if (makrodefineaction.state()==0 ||
  2731.         makrodefineaction.parameter()==0)
  2732.     {    Warning(String(62),String(1),window);
  2733.         makrodefineaction.start();
  2734.     }
  2735.     else makrodefineaction.advance();
  2736. }
  2737.  
  2738. int MakroDefineAction::rektest (Object *o)
  2739. // test if o is constructable from the parameters
  2740. {    Object *ol[MAXDEP];
  2741.     int i,n;
  2742.     if (o->mark) return 1;
  2743.     o->mark.set();
  2744.     n=o->dep(ol);
  2745.     if (n==0) return 0;
  2746.     for (i=0; i<n; i++)
  2747.         if (!rektest(ol[i])) return 0;
  2748.     return 1;
  2749. }
  2750.  
  2751. int MakroDefineAction::testmakro ()
  2752. {   ParameterList *t;
  2753.     char s[256];
  2754.     objects.unmark();
  2755.     t=P;
  2756.     while (t) // mark parameters
  2757.     {    t->object()->mark.set();
  2758.         t=t->next();
  2759.     }
  2760.     t=T;
  2761.     while (t) // check targets and construction steps
  2762.     {   if (!rektest(t->object()))
  2763.         {    sprintf(s,String(67),t->object()->name());
  2764.             Warning(s,String(1),window);
  2765.             return 0;
  2766.         }
  2767.         t=t->next();
  2768.     }
  2769.     return 1;
  2770. }
  2771.  
  2772. int MakroDefineAction::testmakro (Object *o)
  2773. {   ParameterList *t;
  2774.     char s[256];
  2775.     objects.unmark();
  2776.     t=P;
  2777.     while (t) // mark parameters
  2778.     {    t->object()->mark.set();
  2779.         t=t->next();
  2780.     }
  2781.     if (!rektest(o))
  2782.     {    sprintf(s,String(67),o->name());
  2783.         Warning(s,String(1),window);
  2784.         return 0;
  2785.     }
  2786.     return 1;
  2787. }
  2788.  
  2789. void domakrodefine ()
  2790. // menu: Define Macro
  2791. {    if (makrodefineaction.state()!=2 ||
  2792.             makrodefineaction.invalid())
  2793.     {    Warning(String(66),String(1),window);
  2794.         return;
  2795.     }
  2796.     Dialog d(window,IDD_MakroName,help,2080);
  2797.     StringItem name(ID_MakroName,d,"");
  2798.     allover :
  2799.     d.carryout();
  2800.     if (d.result()!=Dialog::ok) return;
  2801.     if (!makrodefineaction.testmakro()) return;
  2802.     if (!*(char *)name)
  2803.     {    Warning(String(70),String(1),window);
  2804.         goto allover;
  2805.     }
  2806.     makrodefineaction.createmakro(name);
  2807. }
  2808.  
  2809. class ConstructionStep
  2810. // list to hold the construction steps
  2811. {    ConstructionStep *Next;
  2812.     String S;
  2813.     public :
  2814.     ConstructionStep (char *s) : S(s),Next(0) {}
  2815.     ~ConstructionStep ()
  2816.     {    if (Next) delete Next;
  2817.     }
  2818.     ConstructionStep *next () { return Next; }
  2819.     void next (ConstructionStep *s) { Next=s; }
  2820.     char *step () { return S; }
  2821.     void append (ConstructionStep *s)
  2822.     {    if (!Next) Next=s;
  2823.         else Next->append(s);
  2824.     }
  2825. };
  2826.  
  2827. Dialog makrosdialog(window,IDD_Makros,help,2060);
  2828.  
  2829. Count makrocount(1000); // menu id count
  2830.  
  2831. class Makro
  2832. // Class to hold a Makro
  2833. // Includes name, paramters and construction steps
  2834. {    Makro *Next,*Prev;
  2835.     ParameterList *P; // List of parameters
  2836.     String Name; // The makro name
  2837.     ConstructionStep *Step; // List of construction steps
  2838.     int C; // Number for menu ID
  2839.     public :
  2840.     Makro (ParameterList *p, ParameterList *t,
  2841.         char *name);
  2842.     Makro (char *name) :
  2843.         P(0),Next(0),Prev(0),Step(0),Name(name),C(makrocount.count())
  2844.     {}
  2845.     ~Makro ()
  2846.     {    if (P) delete P;
  2847.         if (Step) delete Step;
  2848.     }
  2849.     Makro *next () { return Next; }
  2850.     void next (Makro *m) { Next=m; }
  2851.     Makro *prev () { return Prev; }
  2852.     void prev (Makro *m) { Prev=m; }
  2853.     char *name () { return Name; }
  2854.     ParameterList *params () { return P; }
  2855.     ConstructionStep *step () { return Step; }
  2856.     Makro * find (char *name)
  2857.     {    if (!strcmp(name,Name)) return this;
  2858.         if (!Next) return 0;
  2859.         else return Next->find(name);
  2860.     }
  2861.     void remove ();
  2862.     int count () { return C; }
  2863.     void save (char *filename);
  2864.     void addparam (char *name, char *prompt, int type)
  2865.     {    ParameterList *pl=new ParameterList(name,prompt,type);
  2866.         if (!P) P=pl;
  2867.         else P->append(pl);
  2868.     }
  2869.     void addstep (char *s)
  2870.     {    ConstructionStep *cs=new ConstructionStep(s);
  2871.         if (!Step) Step=cs;
  2872.         else Step->append(cs);
  2873.     }
  2874. };
  2875.  
  2876. Makro *makros=0;
  2877.  
  2878. class MakrosItem : public ListItem
  2879. // list box handling class for makro choice
  2880. {    public :
  2881.     MakrosItem() : ListItem(ID_Makros,makrosdialog) {}
  2882.     virtual void init ();
  2883.     virtual void notify ();
  2884. } makrositem;
  2885.  
  2886. void MakrosItem::init ()
  2887. {   int count=0;
  2888.     Makro *m=makros;
  2889.     while (m)
  2890.     {    insert(m->name());
  2891.         m=m->next();
  2892.         count++;
  2893.     }
  2894.     select(count-1);
  2895. }
  2896.  
  2897. void MakrosItem::notify ()
  2898. {    finish();
  2899. }
  2900.  
  2901. void Makro::remove ()
  2902. {    if (Prev) Prev->next(Next);
  2903.     else makros=Next;
  2904.     if (Next) Next->prev(Prev);
  2905.     Next=0; Prev=0;
  2906.     menu.removeitem(C,600);
  2907. }
  2908.  
  2909.  
  2910. Makro::Makro (ParameterList *p, ParameterList *t,
  2911.     char *name) :
  2912.         Name(name),P(p),Step(0),Next(0),Prev(0),
  2913.         C(makrocount.count())
  2914. {   ParameterList *ol=p;
  2915.     while (ol) // get types of parameters and their names
  2916.         // objects are then irrelevant.
  2917.     {    ol->objectclass(ol->object()->objectclass());
  2918.         ol->name(ol->object()->name());
  2919.         ol=ol->next();
  2920.     }
  2921.     Object *o=objects.first();
  2922.     while (o)
  2923.     {   if (o->mark && !makrodefineaction.isparam(o))
  2924.         {   ConstructionStep *s=new ConstructionStep(o->write());
  2925.             if (*(char *)s->step())
  2926.             {    if (!Step) Step=s;
  2927.                 else Step->append(s);
  2928.             }
  2929.         }
  2930.         o=o->next();
  2931.     }
  2932. }
  2933.  
  2934. void domakromenu ();
  2935.  
  2936. void MakroDefineAction::createmakro (char *name)
  2937. {   Makro *m;
  2938.     char s[256];
  2939.     if (makros && (m=makros->find(name))!=0)
  2940.     {   sprintf(s,String(72),m->name(),window);
  2941.         if (Question(s,String(1),window)!=Answers::yes) return;
  2942.         m->remove(); delete m;
  2943.     }
  2944.     m=new Makro(P,T,name);
  2945.     P=0; window.abort();
  2946.     if (makros)
  2947.     {    m->next(makros);
  2948.         makros->prev(m);
  2949.     }
  2950.     makros=m;
  2951.     menu.additem(m->count(),domakromenu,m->name(),600,0);
  2952. }
  2953.  
  2954. void MakroDefineAction::createmakro (Makro *m)
  2955. {   char s[256];
  2956.     Makro *m1;
  2957.     if (makros && (m1=makros->find(m->name()))!=0)
  2958.     {   sprintf(s,String(72),m->name(),window);
  2959.         if (Question(s,String(1),window)!=Answers::yes) return;
  2960.         m1->remove(); delete m1;
  2961.     }
  2962.     if (makros)
  2963.     {    m->next(makros);
  2964.         makros->prev(m);
  2965.     }
  2966.     makros=m;
  2967.     menu.additem(m->count(),domakromenu,m->name(),600,0);
  2968. }
  2969.  
  2970. char * TranslationList::translate (char *ps)
  2971. {    if (!strcmp(ps,Pseudo)) return Original;
  2972.     else
  2973.     {    if (!Next) return 0;
  2974.         else return Next->translate(ps);
  2975.     }
  2976. }
  2977.  
  2978. class MakroRunAction : public Action
  2979. // action to run a makro
  2980. // lets the user choose parameters
  2981. {    Makro *Running;
  2982.     ParameterList *Param;
  2983.     TranslationList *TL;
  2984.     public :
  2985.     MakroRunAction () : Running(0),Param(0),TL(0) {}
  2986.     virtual void inform ();
  2987.     virtual void start ();
  2988.     int choose ();
  2989.     void menuchoose (int id);
  2990.     void startover ();
  2991.     virtual void abort ();
  2992.     virtual void perform (long c, long r);
  2993. } makrorunaction;
  2994.  
  2995. void MakroRunAction::inform ()
  2996. {   static char s[256];
  2997.     if (Running) sprintf(s,"%s : ",Running->name());
  2998.     else sprintf(s,"???");
  2999.     if (Param) strcat(s,Param->prompt());
  3000.     tools.inform(s);
  3001. }
  3002.  
  3003. void MakroRunAction::start ()
  3004. {    Param=Running->params();
  3005.     if (TL) delete TL;
  3006.     TL=0;
  3007. }
  3008.  
  3009. void MakroRunAction::startover ()
  3010. {    Param=Running->params();
  3011.     if (TL) delete TL;
  3012.     TL=0;
  3013.     objects.unhighlight(); objects.redraw();
  3014.     inform();
  3015. }
  3016.  
  3017. void MakroRunAction::abort ()
  3018. {    Param=0; objects.unhighlight(); objects.redraw();
  3019.     if (TL) delete TL;
  3020.     TL=0;
  3021. }
  3022.  
  3023. void MakroRunAction::perform (long c, long r)
  3024. {   if (!Running) return;
  3025.     double x=window.x(c),y=window.y(r);
  3026.     Object *o;
  3027.     if (!objects.select(x,y,o,Param->objectclass())) return;
  3028.     o->highlight.set(); objects.redraw();
  3029.     TranslationList *tl=new TranslationList(o->name(),Param->name());
  3030.     if (!TL) TL=tl;
  3031.     else TL->append(tl);
  3032.     Param=Param->next();
  3033.     if (!Param) // last parameter reached
  3034.     {   ConstructionStep *s=Running->step();
  3035.         translation=TL;
  3036.         while (s)
  3037.         {    if (!iolist.interpret(s->step())) break;
  3038.             s=s->next();
  3039.         }
  3040.         translation=0;
  3041.         startover();
  3042.     }
  3043.     else inform();
  3044. }
  3045.  
  3046. int MakroRunAction::choose ()
  3047. {    if (!makros)
  3048.     {    Warning(String(71),String(1),window);
  3049.         window.old();
  3050.         return 0;
  3051.     }
  3052.     makrosdialog.carryout(); // Choose between avail. Makros
  3053.     if (makrosdialog.result()!=Dialog::ok)
  3054.     {    window.old(); return 0;
  3055.     }
  3056.     int n=makrositem;
  3057.     Running=makros;
  3058.     while (n>0)
  3059.     {    Running=Running->next();
  3060.         n--;
  3061.     }
  3062.     return 1;
  3063. }
  3064.  
  3065. void MakroRunAction::menuchoose (int id)
  3066. {    Makro *m=makros;
  3067.     while (m)
  3068.     {    if (m->count()==id) break;
  3069.         m=m->next();
  3070.     }
  3071.     Running=m;
  3072. }
  3073.  
  3074. void domakrorun ()
  3075. // menu: run makro (F7)
  3076. {    if (!makros) return;
  3077.     if (!makrorunaction.choose()) return;
  3078.     window.action(makrorunaction);
  3079. }
  3080.  
  3081. Makro *selmakro ()
  3082. {    if (!makros) return 0;
  3083.     makrosdialog.carryout(); // Choose between avail. Makros
  3084.     if (makrosdialog.result()!=Dialog::ok) return 0;
  3085.     int n=makrositem;
  3086.     Makro *m=makros;
  3087.     while (n>0)
  3088.     {    m=m->next();
  3089.         n--;
  3090.     }
  3091.     return m;
  3092. }
  3093.  
  3094. void domakromenu ()
  3095. {    makrorunaction.menuchoose(menu.command());
  3096.     window.action(makrorunaction);
  3097. }
  3098.  
  3099. FileSelector makrosout(window,String(73),1,String(74),String(76));
  3100. FileSelector makrosin(window,String(73),1,String(75),String(77));
  3101.  
  3102. void Makro::save (char *filename)
  3103. {    FILE *out=fopen(filename,"w");
  3104.     char s[256];
  3105.     if (!out)
  3106.     {   sprintf(s,String(40),filename);
  3107.         Warning(s,String(1),window);
  3108.         return;
  3109.     }
  3110.     fprintf(out,"N:%s\n",name());
  3111.     ParameterList *p=P;
  3112.     while (p)
  3113.     {    fprintf(out,"P:%s\n",p->name());
  3114.         fprintf(out,"L:%s\n",p->prompt());
  3115.         switch (p->objectclass()&
  3116.             (Object::point|Object::line|Object::circle))
  3117.         {    case Object::point : fprintf(out,"T:point\n"); break;
  3118.             case Object::line : fprintf(out,"T:line\n"); break;
  3119.             case Object::circle : fprintf(out,"T:circle\n"); break;
  3120.         }
  3121.         p=p->next();
  3122.     }
  3123.     ConstructionStep *st=Step;
  3124.     while (st)
  3125.     {    fprintf(out,"S:%s",st->step());
  3126.         st=st->next();
  3127.     }
  3128.     fclose(out);
  3129.     if (ferror(out))
  3130.     {   sprintf(s,String(41),filename);
  3131.         Warning(s,String(1),window);
  3132.         return;
  3133.     }
  3134. }
  3135.  
  3136. void domakrosave ()
  3137. // menu: save makro
  3138. {   Makro *m=selmakro();
  3139.     if (!m) return;
  3140.     String name(makrosout.select());
  3141.     if (name.empty()) return;
  3142.     if (!*name.extension()) name.extension(String(79));
  3143.     m->save(name);
  3144. }
  3145.  
  3146. void domakroload ()
  3147. // menu: load makro
  3148. {   Makro *m;
  3149.     String name(makrosin.select());
  3150.     if (name.empty()) return;
  3151.     FILE *in=fopen(name,"r");
  3152.     char s[512],sw[612],pprompt[256],pname[256];
  3153.     int c;
  3154.     if (!in)
  3155.     {   sprintf(s,String(40),name);
  3156.         Warning(s,String(1),window);
  3157.         return;
  3158.     }
  3159.     if (!fgets(s,500,in)) goto error;
  3160.     stripnl(s);
  3161.     if (strncmp("N:",s,2)) goto error;
  3162.     m=new Makro(s+2);
  3163.     while(1)
  3164.     {    if (!fgets(s,500,in)) goto error;
  3165.         stripnl(s);
  3166.         if (!strncmp("S:",s,2)) break;
  3167.         if (strncmp("P:",s,2)) goto error;
  3168.         strcpy(pname,s+2);
  3169.         if (!fgets(s,500,in)) goto error;
  3170.         stripnl(s);
  3171.         if (strncmp("L:",s,2)) goto error;
  3172.         strcpy(pprompt,s+2);
  3173.         if (!fgets(s,500,in)) goto error;
  3174.         stripnl(s);
  3175.         if (strncmp("T:",s,2)) goto error;
  3176.         if (!strcmp(s+2,"point")) c=Object::point;
  3177.         else if (!strcmp(s+2,"line")) c=Object::line;
  3178.         else if (!strcmp(s+2,"circle")) c=Object::circle;
  3179.         else goto error;
  3180.         m->addparam(pname,pprompt,c);
  3181.     }
  3182.     while (!feof(in))
  3183.     {   if (strncmp("S:",s,2)) goto error;
  3184.         m->addstep(s+2);
  3185.         if (!fgets(s,500,in)) break;
  3186.     }
  3187.     fclose(in);
  3188.     makrodefineaction.createmakro(m);
  3189.     return;
  3190.     error :
  3191.     fclose(in);
  3192.     sprintf(sw,String(78),s);
  3193.     Warning(sw,String(1),window);
  3194. }
  3195.  
  3196. void domakrodelete ()
  3197. // menu: Delete Makro
  3198. {   Makro *m=selmakro();
  3199.     if (!m) return;
  3200.     m->remove();
  3201. }
  3202.  
  3203. // ******** Tools dialog ***************
  3204.  
  3205. class Values : public ValuesetItem
  3206. {    public :
  3207.     Values () : ValuesetItem(ID_Values,tools) {}
  3208.     virtual void init ();
  3209.     virtual void notify ();
  3210.     void call (char key);
  3211.     void shift (int n);
  3212. } values;
  3213.  
  3214. const int idn=18;
  3215. char ids[idn]=
  3216. {    IDBM_Point,IDBM_Line,IDBM_Segment,IDBM_Ray,IDBM_Circle,
  3217.     IDBM_Move,IDBM_Moveon,IDBM_Pointon,
  3218.     IDBM_Intersect,IDBM_Track,
  3219.     IDBM_Hide,IDBM_Edit,IDBM_Delete,
  3220.     IDBM_Lot,IDBM_Parallel,IDBM_Circle3,
  3221.     IDBM_Middle,IDBM_Angle
  3222. };
  3223. Action *actions[idn]=
  3224. {    &pointaction,&lineaction,&segmentaction,&rayaction,&circleaction,
  3225.     &moveaction,&moveonaction,&pointonaction,
  3226.     &intersectionaction,&trackaction,
  3227.     &hideaction,&editaction,&deleteaction,
  3228.     &rectangularaction,¶llelaction,&circle3action,
  3229.     &middleaction,&angleaction
  3230. };
  3231.  
  3232. class Value : public Bitmap
  3233. {   int Id,Col;
  3234.     char Key;
  3235.     Action *A;
  3236.     public :
  3237.     Value (int id, int col, char key, Action &a) : Bitmap(id)
  3238.     {    Id=id; A=&a; Col=col; Key=key;
  3239.         values.setbitmap(1,col,*this);
  3240.     }
  3241.     Action *action () { return A; }
  3242.     int key () { return Key; }
  3243. };
  3244.  
  3245. Value *value[idn];
  3246.  
  3247. void Values::init ()
  3248. {    int i;
  3249.     String s(22);
  3250.     char *keys=s;
  3251.     for (i=0; i<idn; i++)
  3252.     {    value[i]=new Value(ids[i],i+1,keys[i],*actions[i]);
  3253.     }
  3254. }
  3255.  
  3256. void Values::notify ()
  3257. {   window.action(*value[col()-1]->action());
  3258. }
  3259.  
  3260. void Values::call (char key)
  3261. {   int i;
  3262.     key=toupper(key);
  3263.     for (i=0; i<idn; i++)
  3264.     {    if (value[i]->key()==key)
  3265.         {    window.action(*value[i]->action());
  3266.             select(1,i+1);
  3267.             return;
  3268.         }
  3269.     }
  3270. }
  3271.  
  3272. void Values::shift (int n)
  3273. {    n+=col()-1;
  3274.     if (n>=idn) n-=idn;
  3275.     if (n<0) n+=idn;
  3276.     select(1,n+1);
  3277. }
  3278.  
  3279. int MainWindow::key (int flags, int code, int scan)
  3280. {   if (flags&Keycode::up) return 0;
  3281.     if (flags&Keycode::virtualkey)
  3282.     {   switch(scan)
  3283.         {    case VK_LEFT : values.shift(-1); break;
  3284.             case VK_RIGHT : values.shift(1); break;
  3285.             case VK_ESC :
  3286.                 window.abort(); break;
  3287.         }
  3288.     }
  3289.     else values.call(code);
  3290.     return 0;
  3291. }
  3292.  
  3293. int ToolDialog::key (int flags, int code, int scan)
  3294. {   if (flags&Keycode::virtualkey && scan==VK_ESC)
  3295.     {    window.abort(); return 1;
  3296.     }
  3297.     values.call(code);
  3298.     return 1;
  3299. }
  3300.  
  3301. // ********* handle clicks ***********
  3302.  
  3303. void MainWindow::clicked (long c, long r, clicktype click,
  3304.     int state)
  3305. {   if (A->drag) // drag action active
  3306.     {    if (click==button1down || click==mousemove ||
  3307.                 click==button1up ||
  3308.             click==button2down || click==button2up)
  3309.                 A->dragperform(click,c,r);
  3310.         if (click==button2up && Old) old();
  3311.             // right mouse drag finished
  3312.     }
  3313.     else if (click==button1down) A->perform(c,r);
  3314.     else if (click==button2down)
  3315.     {   action(moveaction);
  3316.         A->dragperform(click,c,r);
  3317.     }
  3318. }
  3319.  
  3320. // ********* Menu Entries **********
  3321.  
  3322. void doexit ()
  3323. {    if (window.close()) exit(0);
  3324. }
  3325.  
  3326. void dohidden ()
  3327. {    window.showhidden.toggle();
  3328.     objects.redraw();
  3329.     menu.check(IDM_Hidden,window.showhidden);
  3330. }
  3331.  
  3332. void dohelp ()
  3333. {   switch (menu.command())
  3334.     {    case IDM_General : help.general(); break;
  3335.         case IDM_Index : help.index(); break;
  3336.         case IDM_Keys : help.display(500); break;
  3337.         case IDM_Content : help.content(); break;
  3338.     }
  3339. }
  3340.  
  3341. void doinfo ()
  3342. {    String s("",256);
  3343.     sprintf(s,String(21),__DATE__);
  3344.     Message(s,String(1),window);
  3345. }
  3346.  
  3347. void doclear ()
  3348. {   if (objects.changed && !window.close()) return;
  3349.     window.abort();
  3350.     objects.clear();
  3351.     objectcolors.defcolor(0);
  3352.     objects.redraw();
  3353.     counts.reset();
  3354.     loadname.copy("");
  3355.     window.settitle();
  3356.     objects.comment().copy("");
  3357. }
  3358.  
  3359. void dobackspace ()
  3360. {   window.abort();
  3361.     if (!objects.first()) return;
  3362.     objects.clear(objects.last()->original());
  3363.     while (1)
  3364.     {    if (!objects.first()) break;
  3365.         if (!objects.last()->original()->hidden()) break;
  3366.         objects.clear(objects.last()->original());
  3367.     }
  3368.     objects.redraw();
  3369. }
  3370.  
  3371. // ****** laoding and saving *******
  3372.  
  3373. char *IO::write (Object &o)
  3374. {   *S=0;
  3375.     resadd(o);
  3376.     reswrite(o);
  3377.     sprintf(end(),"=%s(",Name);
  3378.     depwrite(o);
  3379.     strcat(end(),");\n");
  3380.     return S;
  3381. }
  3382.  
  3383. int Object::setflags (Strings &s)
  3384. {   int i;
  3385.     for (i=1; i<s.n(); i++)
  3386.     {    if (!strncmp(s[i],"hidden",6)) ishidden.set();
  3387.         else if (!strncmp(s[i],"color:",6))
  3388.             setcolor(objectcolors.index((char *)s[i]+6));
  3389.         else if (!strcmp(s[i],"showname"))
  3390.             showname.set();
  3391.         else return setspecialflag(s[i]);
  3392.     }
  3393.     return 1;
  3394. }
  3395.  
  3396. int Input::set (Object &o, int i)
  3397. {   if (translation)
  3398.     {   TranslationList *tl=
  3399.             new TranslationList(o.name(),left()[i][0]);
  3400.         translation->append(tl);
  3401.     }
  3402.     else
  3403.     {    if (objects.find(left()[i][0],0,&o))
  3404.         {   Warning(String(48),String(1),window);
  3405.             o.setname("???");
  3406.             return 0;
  3407.         }
  3408.         o.setname1(left()[i][0]);
  3409.     }
  3410.     if (!o.setflags(left()[i])) return 0;
  3411.     return 1;
  3412. }
  3413.  
  3414. Object *Input::object (int i, int flags)
  3415. {    return objects.find(right()[i],flags);
  3416. }
  3417.  
  3418. void IO::resadd (Object &o)
  3419. {   sprintf(end(),"\"%s\"(",o.name());
  3420.     if (o.ishidden)
  3421.     {   comma();
  3422.         strcat(end(),"hidden");
  3423.     }
  3424.     if (o.truecolor()!=0)
  3425.     {   comma();
  3426.         sprintf(end(),"color:%s",objectcolors.name(o.truecolor()));
  3427.     }
  3428.     if (o.showname)
  3429.     {    comma();
  3430.         sprintf(end(),"showname");
  3431.     }
  3432.     o.writespecialflags(*this);
  3433.     strcat(end(),")");
  3434. }
  3435.  
  3436. void IO::comma ()
  3437. {   if (*(end()-1)!='(') strcat(end(),",");
  3438. }
  3439.  
  3440. void IO::depadd (Object &o)
  3441. {   strcat(end(),"\"");
  3442.     strcat(end(),o.name());
  3443.     strcat(end(),"\"");
  3444. }
  3445.  
  3446. int IOList::interpret (char *line)
  3447. {   if (!input.read(line)) return 0;
  3448.     IO *io=First;
  3449.     while (io)
  3450.     {   if (!strcmp(io->name(),input.name()))
  3451.             return io->interpret(input);
  3452.         io=io->next();
  3453.     }
  3454.     return 0;
  3455. }
  3456.  
  3457. void ObjectList::save (char *filename)
  3458. {   char s[512];
  3459.     Object *o=First;
  3460.     FILE *out=fopen(filename,"w");
  3461.     if (!out)
  3462.     {   sprintf(s,String(40),filename);
  3463.         Warning(s,String(1),window); return;
  3464.     }
  3465.     // save comment
  3466.     char *p=Comment;
  3467.     int lc=0;
  3468.     fprintf(out,"window(%g,%g,%g,%g);\n",
  3469.         window.x1(),window.x2(),window.y1(),window.y2());
  3470.     fprintf(out,"/*\n");
  3471.     while (*p)
  3472.     {    while (*p && *p!=13)
  3473.         {    putc(*p++,out); lc++;
  3474.             if (*p==' ' && lc>60)
  3475.             {   p++;
  3476.                 putc('\n',out);
  3477.                 lc=0;
  3478.             }
  3479.         }
  3480.         if (*p)
  3481.         {    p+=2;
  3482.             if (lc>0) putc('\n',out);
  3483.             putc('\n',out);
  3484.             lc=0;
  3485.         }
  3486.     }
  3487.     if (lc>0) putc('\n',out);
  3488.     fprintf(out,"*/\n");
  3489.     // save objects
  3490.     while (o)
  3491.     {   fprintf(out,"%s",o->write());
  3492.         o=o->next();
  3493.     }
  3494.     if (ferror(out))
  3495.     {    sprintf(s,String(41),filename);
  3496.         Warning(s,String(1),window);
  3497.     }
  3498.     fclose(out);
  3499.     if (ferror(out))
  3500.     {    sprintf(s,String(41),filename);
  3501.         Warning(s,String(1),window);
  3502.     }
  3503.     else changed.clear();
  3504. }
  3505.  
  3506. void ObjectList::load (char *filename)
  3507. {    char s[512];
  3508.     char *p=s+2,*q=Comment;
  3509.     int nl=1;
  3510.     doclear();
  3511.     if (objects.first()) return;
  3512.     FILE *in=fopen(filename,"r");
  3513.     if (!in)
  3514.     {   sprintf(s,String(40),filename);
  3515.         Warning(s,String(1),window); return;
  3516.     }
  3517.     if (!fgets(s,510,in)) goto cont;
  3518.     stripnl(s);
  3519.     if (!strncmp(s,"window(",7))
  3520.     {   double x1,x2,y1,y2;
  3521.         if (sscanf(s,"window(%lg,%lg,%lg,%lg);",&x1,&x2,&y1,&y2)==4)
  3522.             window.setsize(x1,x2,y1,y2);
  3523.         if (!fgets(s,510,in)) goto cont;
  3524.         stripnl(s);
  3525.     }
  3526.     if (strncmp(s,"/*",2)) goto cont;
  3527.     while (!feof(in))
  3528.     {    while (*p)
  3529.         {    *q++=*p++;
  3530.             nl=0;
  3531.             if (q-(char *)Comment>Comment.size()-4)
  3532.             {    *q=0; goto cont;
  3533.             }
  3534.         }
  3535.         if (!fgets(s,510,in)) break;
  3536.         p=s;
  3537.         stripnl(s);
  3538.         if (!strncmp(s,"*/",2)) break;
  3539.         if (s[0])
  3540.         {    if (!nl) *q++=' ';
  3541.         }
  3542.         else
  3543.         {    *q++=13; *q++=10; nl=1;
  3544.         }
  3545.     }
  3546.     *q=0;
  3547.     while (!feof(in))
  3548.     {    if (!fgets(s,510,in)) break;
  3549.         if (!strncmp(s,"//",2)) continue;
  3550.         stripnl(s);
  3551.         cont:
  3552.         if (!iolist.interpret(s))
  3553.         {   Dialog error(window,IDD_Fileerror,help,2020);
  3554.             StringItem line(ID_Errorline,error,s,512);
  3555.             error.carryout();
  3556.             break;
  3557.         }
  3558.     }
  3559.     bitmap->invalid.set();
  3560.     window.update();
  3561.     fclose(in);
  3562.     changed.clear();
  3563. }
  3564.  
  3565. FileSelector out(window,String(47),1,String(42),String(51));
  3566. FileSelector in(window,String(47),0,String(43),String(52));
  3567.  
  3568. void ObjectList::copy ()
  3569. {    Clipboard clip;
  3570.     MetafilePS meta(window);
  3571.     draw(meta);
  3572.     clip.copy(meta);
  3573. }
  3574.  
  3575. void docomment ()
  3576. {    Dialog d(window,IDD_Comment,help,2040);
  3577.     MultilineItem text(IDC_Comment,d,
  3578.         objects.comment(),objects.comment().size());
  3579.     d.carryout();
  3580.     if (d.result()!=Dialog::ok) return;
  3581.     if (strcmp(objects.comment(),text)!=0)
  3582.     {    objects.changed.set();
  3583.         strcpy(objects.comment(),text);
  3584.     }
  3585. }
  3586.  
  3587. void dosaveas ()
  3588. {   String name(out.select());
  3589.     if (name.empty()) return;
  3590.     if (!*name.extension()) name.extension(String(80));
  3591.     loadname.copy(name);
  3592.     objects.save(loadname);
  3593.     loadname.copy(name);
  3594.     window.settitle();
  3595. }
  3596.  
  3597. void dosave ()
  3598. {   if (loadname.empty())
  3599.     {    dosaveas(); return;
  3600.     }
  3601.     objects.save(loadname);
  3602. }
  3603.  
  3604. int MainWindow::close ()
  3605. {   profile.writeint("square",window.square);
  3606.     if (!objects.changed || objects.empty()) return 1;
  3607.     switch (QuestionAbort(String(57),String(1),window))
  3608.     {    case Answers::yes :
  3609.             dosave();
  3610.             break;
  3611.         case Answers::abort : return 0;
  3612.     }
  3613.     return 1;
  3614. }
  3615.  
  3616. void doload ()
  3617. {   String name(in.select());
  3618.     if (name.empty()) return;
  3619.     objects.load(name);
  3620.     loadname.copy(name);
  3621.     docomment();
  3622.     loadname.copy(name);
  3623.     window.settitle();
  3624. }
  3625.  
  3626. void doload (char *name)
  3627. {   objects.load(name);
  3628.     loadname.copy(name);
  3629.     docomment();    loadname.copy(name);
  3630.     window.settitle();
  3631. }
  3632.  
  3633. void docolor ()
  3634. {    Dialog d(window,IDD_Color,help,2030);
  3635.     PointColor coloritem(IDP_Color,d,1,objectcolors.defcolor()+1);
  3636.     d.carryout();
  3637.     if (d.result()!=DID_OK) return;
  3638.     objectcolors.defcolor(coloritem.col()-1);
  3639. }
  3640.  
  3641. void dozoomin ()
  3642. {    window.zoomin();
  3643. }
  3644.  
  3645. void dozoomout ()
  3646. {    window.zoomout();
  3647. }
  3648.  
  3649. void docenter ()
  3650. {    window.center();
  3651. }
  3652.  
  3653. void docopy ()
  3654. {    objects.copy();
  3655. }
  3656.  
  3657. void dosquare ()
  3658. {    window.square.toggle();
  3659.     menu.check(IDM_Square,window.square);
  3660.     if (window.square) window.sized();
  3661. }
  3662.  
  3663. void dofont ()
  3664. {    fontselector.select(window);
  3665.     if (fontselector)
  3666.     {   Font font(fontselector);
  3667.         bitmap->setfont(font);
  3668.         objects.redraw();
  3669.     }
  3670. }
  3671.  
  3672. void dodeletetracks ()
  3673. {    objects.deletetracks();
  3674.     objects.redraw();
  3675. }
  3676.  
  3677. FileSelector savebmp(window,"*.bmp",1,String(59),String(58));
  3678.  
  3679. void dosavebitmap ()
  3680. {    char *name=savebmp.select();
  3681.     if (!name) return;
  3682.     bitmap->save(name);
  3683. }
  3684.  
  3685. //********* Things for the choose selected objects dialog *****
  3686.  
  3687. class ColorCheckItem : public CheckItem
  3688. {   int I;
  3689.     public :
  3690.     ColorCheckItem (int id, Dialog &d, int i, int f) :
  3691.         CheckItem(id,d,f),I(i) {}
  3692.     virtual void notify ()
  3693.     {    objectcolors.choose(I,flag());
  3694.         bitmap->invalid.set();
  3695.         window.update();
  3696.     }
  3697. };
  3698.  
  3699. class ColorButtonItem : public ButtonItem
  3700. {    public :
  3701.     ColorButtonItem (int id, Dialog &d) : ButtonItem(id,d)
  3702.     {}
  3703. };
  3704.  
  3705. class ChooseDialog : public Dialog
  3706. {    static int Colorid[6];
  3707.     static int Buttonid[6];
  3708.     ColorCheckItem *Ci[6];
  3709.     ColorButtonItem *Bi[6];
  3710.     ButtonItem *All,*None;
  3711.     public :
  3712.     ChooseDialog ();
  3713.     ~ChooseDialog ();
  3714.     void all ();
  3715.     void none ();
  3716. };
  3717.  
  3718. class AllItem : public ButtonItem
  3719. {   ChooseDialog *D;
  3720.     public :
  3721.     AllItem (ChooseDialog &d) : ButtonItem(ID_All,d),D(&d) {}
  3722.     virtual void notify();
  3723. };
  3724.  
  3725. class NoneItem : public ButtonItem
  3726. {   ChooseDialog *D;
  3727.     public :
  3728.     NoneItem (ChooseDialog &d) : ButtonItem(ID_None,d),D(&d) {}
  3729.     virtual void notify();
  3730. };
  3731.  
  3732. ChooseDialog::ChooseDialog () :
  3733.     Dialog(window,IDD_ChooseColors,help,2050)
  3734. {    int i;
  3735.     for (i=0; i<6; i++)
  3736.     {    Ci[i]=new ColorCheckItem(Colorid[i],*this,
  3737.             i,objectcolors.chosen(i));
  3738.         Bi[i]=new ColorButtonItem(Buttonid[i],*this);
  3739.     }
  3740.     All=new AllItem(*this);
  3741.     None=new NoneItem(*this);
  3742.     void all ();
  3743.     void none ();
  3744. }
  3745.  
  3746. ChooseDialog::~ChooseDialog ()
  3747. {    int i;
  3748.     for (i=0; i<6; i++)
  3749.     {    delete Ci[i]; delete Bi[i];
  3750.     }
  3751.     delete All;
  3752.     delete None;
  3753. }
  3754.  
  3755. int ChooseDialog::Colorid[6] =
  3756. {    ID_Black,ID_Blue,ID_Pink,ID_Green,ID_Cyan,ID_Brown};
  3757. int ChooseDialog::Buttonid[6] =
  3758. {    ID_B1,ID_B2,ID_B3,ID_B4,ID_B5,ID_B6};
  3759.  
  3760. void AllItem::notify ()
  3761. {    D->all();
  3762. }
  3763.  
  3764. void NoneItem::notify ()
  3765. {    D->none();
  3766. }
  3767.  
  3768. void ChooseDialog::all ()
  3769. {    int i;
  3770.     for (i=0; i<6; i++)
  3771.     {    Ci[i]->reinit(1);
  3772.         Ci[i]->notify();
  3773.     }
  3774. }
  3775.  
  3776. void ChooseDialog::none ()
  3777. {    int i;
  3778.     for (i=0; i<6; i++)
  3779.     {    Ci[i]->reinit(0);
  3780.         Ci[i]->notify();
  3781.     }
  3782. }
  3783.  
  3784. void dochoosecolors ()
  3785. {    ChooseDialog d;
  3786.     int note[6],i;
  3787.     for (i=0; i<6; i++) note[i]=objectcolors.chosen(i);
  3788.     d.carryout();
  3789.     if (d.result()==DID_OK) return;
  3790.     for (i=0; i<6; i++)
  3791.         objectcolors.choose(i,note[i]);
  3792.     bitmap->invalid.set();
  3793.     window.update();
  3794. }
  3795.  
  3796. void dosavepos ()
  3797. {    long x,y,w,h;
  3798.     window.getframe(x,y,w,h);
  3799.     profile.writelong("x",x);
  3800.     profile.writelong("y",y);
  3801.     profile.writelong("w",window.width());
  3802.     profile.writelong("h",window.height());
  3803.     tools.getframe(x,y,w,h);
  3804.     profile.writelong("xd",x);
  3805.     profile.writelong("yd",y);
  3806. }
  3807.  
  3808. // *********** main ****************
  3809.  
  3810. int main (int argc, char *argv[])
  3811. {   window.top();
  3812.     window.active.set();
  3813.     tools.show();
  3814.     menu.add(IDM_Exit,doexit);
  3815.     menu.add(IDM_Hidden,dohidden);
  3816.     menu.add(IDM_General,dohelp);
  3817.     menu.add(IDM_Index,dohelp);
  3818.     menu.add(IDM_Content,dohelp);
  3819.     menu.add(IDM_Keys,dohelp);
  3820.     menu.add(IDM_Product,doinfo);
  3821.     menu.add(IDM_Clear,doclear);
  3822.     menu.add(IDM_Backspace,dobackspace);
  3823.     menu.add(IDM_Saveas,dosaveas);
  3824.     menu.add(IDM_Save,dosave);
  3825.     menu.add(IDM_Load,doload);
  3826.     menu.add(IDM_Color,docolor);
  3827.     menu.add(IDM_Comment,docomment);
  3828.     menu.add(IDM_Zoomin,dozoomin);
  3829.     menu.add(IDM_Zoomout,dozoomout);
  3830.     menu.add(IDM_Center,docenter);
  3831.     menu.add(IDM_Copy,docopy);
  3832.     menu.add(IDM_Font,dofont);
  3833.     menu.add(IDM_DeleteTracks,dodeletetracks);
  3834.     menu.add(IDM_Savebitmap,dosavebitmap);
  3835.     menu.add(IDM_Square,dosquare);
  3836.     menu.add(IDM_ShowSelected,dochoosecolors);
  3837.     menu.add(IDM_SavePosition,dosavepos);
  3838.     menu.add(IDM_MakroParameter,domakroparameter);
  3839.     menu.add(IDM_MakroConstructed,domakroconstructed);
  3840.     menu.add(IDM_MakroDefine,domakrodefine);
  3841.     menu.add(IDM_MakroRun,domakrorun);
  3842.     menu.add(IDM_MakroLoad,domakroload);
  3843.     menu.add(IDM_MakroSave,domakrosave);
  3844.     menu.add(IDM_MakroDelete,domakrodelete);
  3845.     if (argc==2) doload(argv[1]);
  3846.     long x,y,w,h,xd,yd,wd,hd;
  3847.     w=profile.readlong("w",window.width());
  3848.     h=profile.readlong("h",window.height());
  3849.     window.size(w,h);
  3850.     window.getframe(x,y,w,h);
  3851.     x=profile.readlong("x",20);
  3852.     y=profile.readlong("y",program.height()-20-h);
  3853.     window.framepos(x,y);
  3854.     tools.getframe(xd,yd,wd,hd);
  3855.     xd=x; yd=program.height()-20-h-hd-5;
  3856.     xd=profile.readlong("xd",xd);
  3857.     yd=profile.readlong("yd",yd);
  3858.     tools.framepos(xd,yd);
  3859.     window.action(pointaction);
  3860.     window.square=profile.readint("square",0);
  3861.     if (window.square)
  3862.     {    menu.check(IDM_Square,1);
  3863.         window.sized();
  3864.     }
  3865.     window.sizing.set();
  3866.     window.sized();
  3867.     program.loop();    return 0;
  3868. }
  3869.  
  3870.